return t.Extra.(ChanArgs).T
}
-// FuncArgs returns the channel type for TFUNCARGS type t.
+// FuncArgs returns the func type for TFUNCARGS type t.
func (t *Type) FuncArgs() *Type {
t.wantEtype(TFUNCARGS)
return t.Extra.(FuncArgs).T
type funcLayoutTest struct {
rcvr, t Type
size, argsize, retOffset uintptr
- stack []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
+ stack []byte // pointer bitmap: 1 is pointer, 0 is scalar
gc []byte
}
6 * PtrSize,
4 * PtrSize,
4 * PtrSize,
- []byte{1, 0, 1},
+ []byte{1, 0, 1, 0, 1},
[]byte{1, 0, 1, 0, 1},
})
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
+ MOVB $0, 12(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 8(SP)
CALL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
+ MOVB $0, 12(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 8(SP)
CALL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVQ DX, 0(SP)
LEAQ argframe+0(FP), CX
MOVQ CX, 8(SP)
+ MOVB $0, 24(SP)
+ LEAQ 24(SP), AX
+ MOVQ AX, 16(SP)
CALL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVQ DX, 0(SP)
LEAQ argframe+0(FP), CX
MOVQ CX, 8(SP)
+ MOVB $0, 24(SP)
+ LEAQ 24(SP), AX
+ MOVQ AX, 16(SP)
CALL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
+ MOVB $0, 12(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 8(SP)
CALL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVL DX, 0(SP)
LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
+ MOVB $0, 12(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 8(SP)
CALL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW R7, 4(R13)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R13)
+ MOVW $0, R1
+ MOVB R1, 16(R13)
+ ADD $16, R13, R1
+ MOVW R1, 12(R13)
BL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No argsize here, gc generates argsize info at call site.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW R7, 4(R13)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R13)
+ MOVW $0, R1
+ MOVB R1, 16(R13)
+ ADD $16, R13, R1
+ MOVW R1, 12(R13)
BL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$24
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
NO_LOCAL_POINTERS
MOVD R26, 8(RSP)
MOVD $argframe+0(FP), R3
MOVD R3, 16(RSP)
+ MOVB $0, 32(RSP)
+ ADD $32, RSP, R3
+ MOVD R3, 24(RSP)
BL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$24
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40
NO_LOCAL_POINTERS
MOVD R26, 8(RSP)
MOVD $argframe+0(FP), R3
MOVD R3, 16(RSP)
+ MOVB $0, 32(RSP)
+ ADD $32, RSP, R3
+ MOVD R3, 24(RSP)
BL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVV REGCTXT, 8(R29)
MOVV $argframe+0(FP), R1
MOVV R1, 16(R29)
+ MOVB R0, 32(R29)
+ ADDV $32, R29, R1
+ MOVV R1, 24(R29)
JAL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVV REGCTXT, 8(R29)
MOVV $argframe+0(FP), R1
MOVV R1, 16(R29)
+ MOVB R0, 32(R29)
+ ADDV $32, R29, R1
+ MOVV R1, 24(R29)
JAL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW REGCTXT, 4(R29)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R29)
+ MOVB R0, 16(R29)
+ ADD $16, R29, R1
+ MOVW R1, 12(R29)
JAL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
NO_LOCAL_POINTERS
MOVW REGCTXT, 4(R29)
MOVW $argframe+0(FP), R1
MOVW R1, 8(R29)
+ MOVB R0, 16(R29)
+ ADD $16, R29, R1
+ MOVW R1, 12(R29)
JAL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R11, FIXED_FRAME+0(R1)
MOVD $argframe+0(FP), R3
MOVD R3, FIXED_FRAME+8(R1)
+ MOVB R0, FIXED_FRAME+24(R1)
+ ADD $FIXED_FRAME+24, R1, R3
+ MOVD R3, FIXED_FRAME+16(R1)
BL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R11, FIXED_FRAME+0(R1)
MOVD $argframe+0(FP), R3
MOVD R3, FIXED_FRAME+8(R1)
+ MOVB R0, FIXED_FRAME+24(R1)
+ ADD $FIXED_FRAME+24, R1, R3
+ MOVD R3, FIXED_FRAME+16(R1)
BL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
+ MOVB R0, 32(R15)
+ ADD $32, R15, R3
+ MOVD R3, 24(R15)
BL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
+ MOVB R0, 32(R15)
+ ADD $32, R15, R3
+ MOVD R3, 24(R15)
BL ·callMethod(SB)
RET
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD CTXT, 0(SP)
I64Add
I64Store $8
+ MOVB $0, 24(SP)
+ MOVD $24(SP), 16(SP)
+
CALL ·callReflect(SB)
RET
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
NO_LOCAL_POINTERS
MOVD CTXT, 0(SP)
I64Add
I64Store $8
+ MOVB $0, 24(SP)
+ MOVD $24(SP), 16(SP)
+
CALL ·callMethod(SB)
RET
var ft *rtype
var s *bitVector
if rcvr != nil {
- ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
+ ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), rcvr.(*rtype))
} else {
- ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
+ ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), nil)
}
frametype = ft
for i := uint32(0); i < s.n; i++ {
// makeFuncImpl is the closure value implementing the function
// returned by MakeFunc.
-// The first two words of this type must be kept in sync with
+// The first three words of this type must be kept in sync with
// methodValue and runtime.reflectMethodValue.
// Any changes should be reflected in all three.
type makeFuncImpl struct {
- code uintptr
- stack *bitVector
- typ *funcType
- fn func([]Value) []Value
+ code uintptr
+ stack *bitVector // ptrmap for both args and results
+ argLen uintptr // just args
+ ftyp *funcType
+ fn func([]Value) []Value
}
// MakeFunc returns a new function of the given Type
code := **(**uintptr)(unsafe.Pointer(&dummy))
// makeFuncImpl contains a stack map for use by the runtime
- _, _, _, stack, _ := funcLayout(t, nil)
+ _, argLen, _, stack, _ := funcLayout(ftyp, nil)
- impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
+ impl := &makeFuncImpl{code: code, stack: stack, argLen: argLen, ftyp: ftyp, fn: fn}
return Value{t, unsafe.Pointer(impl), flag(Func)}
}
// word in the passed-in argument frame.
func makeFuncStub()
-// The first two words of this type must be kept in sync with
+// The first 3 words of this type must be kept in sync with
// makeFuncImpl and runtime.reflectMethodValue.
// Any changes should be reflected in all three.
type methodValue struct {
fn uintptr
- stack *bitVector
+ stack *bitVector // ptrmap for both args and results
+ argLen uintptr // just args
method int
rcvr Value
}
rcvr := Value{v.typ, v.ptr, fl}
// v.Type returns the actual type of the method value.
- funcType := v.Type().(*rtype)
+ ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
// Indirect Go func value (dummy) to obtain
// actual code address. (A Go func value is a pointer
code := **(**uintptr)(unsafe.Pointer(&dummy))
// methodValue contains a stack map for use by the runtime
- _, _, _, stack, _ := funcLayout(funcType, nil)
+ _, argLen, _, stack, _ := funcLayout(ftyp, nil)
fv := &methodValue{
fn: code,
stack: stack,
+ argLen: argLen,
method: int(v.flag) >> flagMethodShift,
rcvr: rcvr,
}
// but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method)
- return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
+ return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
}
// methodValueCall is an assembly function that is the code half of
}
type layoutKey struct {
- t *rtype // function signature
- rcvr *rtype // receiver type, or nil if none
+ ftyp *funcType // function signature
+ rcvr *rtype // receiver type, or nil if none
}
type layoutType struct {
// The returned type exists only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in
// the name for possible debugging use.
-func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
+func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
if t.Kind() != Func {
panic("reflect: funcLayout of non-func type")
}
return lt.t, lt.argSize, lt.retOffset, lt.stack, lt.framePool
}
- tt := (*funcType)(unsafe.Pointer(t))
-
// compute gc program & stack bitmap for arguments
ptrmap := new(bitVector)
var offset uintptr
}
offset += ptrSize
}
- for _, arg := range tt.in() {
+ for _, arg := range t.in() {
offset += -offset & uintptr(arg.align-1)
addTypeBits(ptrmap, offset, arg)
offset += arg.size
}
- argN := ptrmap.n
argSize = offset
if runtime.GOARCH == "amd64p32" {
offset += -offset & (8 - 1)
}
offset += -offset & (ptrSize - 1)
retOffset = offset
- for _, res := range tt.out() {
+ for _, res := range t.out() {
offset += -offset & uintptr(res.align-1)
addTypeBits(ptrmap, offset, res)
offset += res.size
} else {
x.kind |= kindNoPointers
}
- ptrmap.n = argN
var s string
if rcvr != nil {
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
- t := v.typ
+ t := (*funcType)(unsafe.Pointer(v.typ))
var (
fn unsafe.Pointer
rcvr Value
// NOTE: This function must be marked as a "wrapper" in the generated code,
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callReflect".
-func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
- ftyp := ctxt.typ
+//
+// ctxt is the "closure" generated by MakeFunc.
+// frame is a pointer to the arguments to that closure on the stack.
+// retValid points to a boolean which should be set when the results
+// section of frame is set.
+func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
+ ftyp := ctxt.ftyp
f := ctxt.fn
// Copy argument frame into Values.
}
}
+ // Announce that the return values are valid.
+ // After this point the runtime can depend on the return values being valid.
+ *retValid = true
+
+ // We have to make sure that the out slice lives at least until
+ // the runtime knows the return values are valid. Otherwise, the
+ // return values might not be scanned by anyone during a GC.
+ // (out would be dead, and the return slots not yet alive.)
+ runtime.KeepAlive(out)
+
// runtime.getArgInfo expects to be able to find ctxt on the
// stack when it finds our caller, makeFuncStub. Make sure it
// doesn't get garbage collected.
// The return value rcvrtype gives the method's actual receiver type.
// The return value t gives the method type signature (without the receiver).
// The return value fn is a pointer to the method code.
-func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
+func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *rtype, t *funcType, fn unsafe.Pointer) {
i := methodIndex
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
}
rcvrtype = iface.itab.typ
fn = unsafe.Pointer(&iface.itab.fun[i])
- t = tt.typeOff(m.typ)
+ t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
} else {
rcvrtype = v.typ
ms := v.typ.exportedMethods()
}
ifn := v.typ.textOff(m.ifn)
fn = unsafe.Pointer(&ifn)
- t = v.typ.typeOff(m.mtyp)
+ t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
}
return
}
// NOTE: This function must be marked as a "wrapper" in the generated code,
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callMethod".
-func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
+//
+// ctxt is the "closure" generated by makeVethodValue.
+// frame is a pointer to the arguments to that closure on the stack.
+// retValid points to a boolean which should be set when the results
+// section of frame is set.
+func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool) {
rcvr := ctxt.rcvr
rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
// Make a new frame that is one word bigger so we can store the receiver.
- args := framePool.Get().(unsafe.Pointer)
+ // This space is used for both arguments and return values.
+ scratch := framePool.Get().(unsafe.Pointer)
// Copy in receiver and rest of args.
// Avoid constructing out-of-bounds pointers if there are no args.
- storeRcvr(rcvr, args)
+ storeRcvr(rcvr, scratch)
if argSize-ptrSize > 0 {
- typedmemmovepartial(frametype, add(args, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
+ typedmemmovepartial(frametype, add(scratch, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
}
// Call.
- // Call copies the arguments from args to the stack, calls fn,
- // and then copies the results back into args.
- call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
+ // Call copies the arguments from scratch to the stack, calls fn,
+ // and then copies the results back into scratch.
+ call(frametype, fn, scratch, uint32(frametype.size), uint32(retOffset))
// Copy return values. On amd64p32, the beginning of return values
// is 64-bit aligned, so the caller's frame layout (which doesn't have
}
// This copies to the stack. Write barriers are not needed.
memmove(add(frame, callerRetOffset, "frametype.size > retOffset"),
- add(args, retOffset, "frametype.size > retOffset"),
+ add(scratch, retOffset, "frametype.size > retOffset"),
frametype.size-retOffset)
}
- // Put the args scratch space back in the pool.
- typedmemclr(frametype, args)
- framePool.Put(args)
+ // Tell the runtime it can now depend on the return values
+ // being properly initialized.
+ *retValid = true
+
+ // Clear the scratch space and put it back in the pool.
+ // This must happen after the statement above, so that the return
+ // values will always be scanned by someone.
+ typedmemclr(frametype, scratch)
+ framePool.Put(scratch)
// See the comment in callReflect.
runtime.KeepAlive(ctxt)
// reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
// and reflect.methodValue.
type reflectMethodValue struct {
- fn uintptr
- stack *bitvector // args bitmap
+ fn uintptr
+ stack *bitvector // ptrmap for both args and results
+ argLen uintptr // just args
}
// getArgInfoFast returns the argument frame information for a call to f.
// These take a *reflect.methodValue as their
// context register.
var mv *reflectMethodValue
+ var retValid bool
if ctxt != nil {
// This is not an actual call, but a
// deferred call. The function value
// 0(SP).
arg0 := frame.sp + sys.MinFrameSize
mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
+ // Figure out whether the return values are valid.
+ // Reflect will update this value after it copies
+ // in the return values.
+ retValid = *(*bool)(unsafe.Pointer(arg0 + 3*sys.PtrSize))
}
if mv.fn != f.entry {
print("runtime: confused by ", funcname(f), "\n")
}
bv := mv.stack
arglen = uintptr(bv.n * sys.PtrSize)
+ if !retValid {
+ arglen = uintptr(mv.argLen) &^ (sys.PtrSize - 1)
+ }
argmap = bv
}
}
--- /dev/null
+// run
+
+// Copyright 2018 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.
+
+// Make sure return values are always scanned, when
+// calling methods (+functions, TODO) with reflect.
+
+package main
+
+import (
+ "reflect"
+ "runtime/debug"
+ "sync"
+)
+
+func main() {
+ debug.SetGCPercent(1) // run GC frequently
+ var wg sync.WaitGroup
+ for i := 0; i < 20; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 2000; i++ {
+ _test()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+type Stt struct {
+ Data interface{}
+}
+
+type My struct {
+ b byte
+}
+
+func (this *My) Run(rawData []byte) (Stt, error) {
+ var data string = "hello"
+ stt := Stt{
+ Data: data,
+ }
+ return stt, nil
+}
+
+func _test() (interface{}, error) {
+ f := reflect.ValueOf(&My{}).MethodByName("Run")
+ if method, ok := f.Interface().(func([]byte) (Stt, error)); ok {
+ s, e := method(nil)
+ // The bug in issue27695 happens here, during the return
+ // from the above call (at the end of reflect.callMethod
+ // when preparing to return). The result value that
+ // is assigned to s was not being scanned if GC happens
+ // to occur there.
+ i := interface{}(s)
+ return i, e
+ }
+ return nil, nil
+}
--- /dev/null
+// run
+
+// Copyright 2018 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.
+
+// Make sure return values aren't scanned until they
+// are initialized, when calling functions and methods
+// via reflect.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+var badPtr uintptr
+
+var sink []byte
+
+func init() {
+ // Allocate large enough to use largeAlloc.
+ b := make([]byte, 1<<16-1)
+ sink = b // force heap allocation
+ // Any space between the object and the end of page is invalid to point to.
+ badPtr = uintptr(unsafe.Pointer(&b[len(b)-1])) + 1
+}
+
+func f(d func() *byte) *byte {
+ // Initialize callee args section with a bad pointer.
+ g(badPtr)
+
+ // Then call a function which returns a pointer.
+ // That return slot starts out holding a bad pointer.
+ return d()
+}
+
+//go:noinline
+func g(x uintptr) {
+}
+
+type T struct {
+}
+
+func (t *T) Foo() *byte {
+ runtime.GC()
+ return nil
+}
+
+func main() {
+ // Functions
+ d := reflect.MakeFunc(reflect.TypeOf(func() *byte { return nil }),
+ func(args []reflect.Value) []reflect.Value {
+ runtime.GC()
+ return []reflect.Value{reflect.ValueOf((*byte)(nil))}
+ }).Interface().(func() *byte)
+ f(d)
+
+ // Methods
+ e := reflect.ValueOf(&T{}).Method(0).Interface().(func() *byte)
+ f(e)
+}