Commit 85138da8 authored by Keith Randall's avatar Keith Randall

reflect: prevent the callXX routines from calling makeFuncStub

and methodValueCall directly.  Instead, we inline their behavior
inside of reflect.call.

This change is required because otherwise we have a situation where
reflect.callXX calls makeFuncStub, neither of which knows the
layout of the args passed between them.  That's bad for
precise gc & stack copying.

Fixes #6619.

R=golang-dev, dvyukov, rsc, iant, khr
CC=golang-dev
https://golang.org/cl/26970044
parent c792bde9
......@@ -3616,3 +3616,27 @@ func (x *exhaustive) Choose(max int) int {
func (x *exhaustive) Maybe() bool {
return x.Choose(2) == 1
}
func GCFunc(args []Value) []Value {
runtime.GC()
return []Value{}
}
func TestReflectFuncTraceback(t *testing.T) {
f := MakeFunc(TypeOf(func() {}), GCFunc)
f.Call([]Value{})
}
func (p Point) GCMethod(k int) int {
runtime.GC()
return k + p.x
}
func TestReflectMethodTraceback(t *testing.T) {
p := Point{3, 4}
m := ValueOf(p).MethodByName("GCMethod")
i := ValueOf(m.Interface()).Call([]Value{ValueOf(5)})[0].Int()
if i != 8 {
t.Errorf("Call returned %d; want 8", i)
}
}
......@@ -358,6 +358,11 @@ func (v Value) CallSlice(in []Value) []Value {
return v.call("CallSlice", in)
}
var makeFuncStubFn = makeFuncStub
var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
var methodValueCallFn = methodValueCall
var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn))
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
......@@ -377,6 +382,17 @@ func (v Value) call(op string, in []Value) []Value {
panic("reflect.Value.Call: call of nil function")
}
// If target is makeFuncStub, short circuit the unpack onto stack /
// pack back into []Value for the args and return values. Just do the
// call directly.
// We need to do this here because otherwise we have a situation where
// reflect.callXX calls makeFuncStub, neither of which knows the
// layout of the args. That's bad for precise gc & stack copying.
x := (*makeFuncImpl)(fn)
if x.code == makeFuncStubCode {
return x.fn(in)
}
isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice {
......@@ -470,6 +486,22 @@ func (v Value) call(op string, in []Value) []Value {
}
off = (off + ptrSize - 1) &^ (ptrSize - 1)
// If the target is methodValueCall, do its work here: add the receiver
// argument and call the real target directly.
// We need to do this here because otherwise we have a situation where
// reflect.callXX calls methodValueCall, neither of which knows the
// layout of the args. That's bad for precise gc & stack copying.
y := (*methodValue)(fn)
if y.fn == methodValueCallCode {
_, fn, rcvr = methodReceiver("call", y.rcvr, y.method)
args = append(args, unsafe.Pointer(nil))
copy(args[1:], args)
args[0] = unsafe.Pointer(rcvr)
ptr = unsafe.Pointer(&args[0])
off += ptrSize
size += ptrSize
}
// Call.
call(fn, ptr, uint32(size))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment