@@ -473,11 +473,14 @@ func (v Value) call(op string, in []Value) []Value {
473
473
// Get function pointer, type.
474
474
t := v .typ
475
475
var (
476
- fn unsafe.Pointer
477
- rcvr iword
476
+ fn unsafe.Pointer
477
+ rcvr Value
478
+ rcvrtype * rtype
478
479
)
479
480
if v .flag & flagMethod != 0 {
480
- t , fn , rcvr = methodReceiver (op , v , int (v .flag )>> flagMethodShift )
481
+ rcvrtype = t
482
+ rcvr = v
483
+ t , fn = methodReceiver (op , v , int (v .flag )>> flagMethodShift )
481
484
} else if v .flag & flagIndir != 0 {
482
485
fn = * (* unsafe .Pointer )(v .ptr )
483
486
} else {
@@ -556,23 +559,26 @@ func (v Value) call(op string, in []Value) []Value {
556
559
}
557
560
nout := t .NumOut ()
558
561
559
- // Compute arg size & allocate.
560
- // This computation is 5g/6g/8g-dependent
561
- // and probably wrong for gccgo, but so
562
- // is most of this function.
563
- size , _ , _ , _ := frameSize (t , v .flag & flagMethod != 0 )
564
-
565
- // Copy into args.
566
- //
567
- // TODO(rsc): This will need to be updated for any new garbage collector.
568
- // For now make everything look like a pointer by allocating
569
- // a []unsafe.Pointer.
570
- args := make ([]unsafe.Pointer , size / ptrSize )
571
- ptr := unsafe .Pointer (& args [0 ])
562
+ // If the target is methodValueCall, do its work here: add the receiver
563
+ // argument and call the real target directly.
564
+ // We need to do this here because otherwise we have a situation where
565
+ // reflect.callXX calls methodValueCall, neither of which knows the
566
+ // layout of the args. That's bad for precise gc & stack copying.
567
+ y := (* methodValue )(fn )
568
+ if y .fn == methodValueCallCode {
569
+ rcvr = y .rcvr
570
+ rcvrtype = rcvr .typ
571
+ t , fn = methodReceiver ("call" , rcvr , y .method )
572
+ }
573
+
574
+ // Compute frame type, allocate a chunk of memory for frame
575
+ frametype := funcLayout (t , rcvrtype )
576
+ args := unsafe_New (frametype )
572
577
off := uintptr (0 )
573
- if v .flag & flagMethod != 0 {
574
- // Hard-wired first argument.
575
- * (* iword )(ptr ) = rcvr
578
+
579
+ // Copy inputs into args.
580
+ if rcvrtype != nil {
581
+ storeRcvr (rcvr , args )
576
582
off = ptrSize
577
583
}
578
584
for i , v := range in {
@@ -581,7 +587,7 @@ func (v Value) call(op string, in []Value) []Value {
581
587
a := uintptr (targ .align )
582
588
off = (off + a - 1 ) &^ (a - 1 )
583
589
n := targ .size
584
- addr := unsafe .Pointer (uintptr (ptr ) + off )
590
+ addr := unsafe .Pointer (uintptr (args ) + off )
585
591
v = v .assignTo ("reflect.Value.Call" , targ , (* interface {})(addr ))
586
592
if v .flag & flagIndir != 0 {
587
593
memmove (addr , v .ptr , n )
@@ -594,35 +600,17 @@ func (v Value) call(op string, in []Value) []Value {
594
600
}
595
601
off = (off + ptrSize - 1 ) &^ (ptrSize - 1 )
596
602
597
- // If the target is methodValueCall, do its work here: add the receiver
598
- // argument and call the real target directly.
599
- // We need to do this here because otherwise we have a situation where
600
- // reflect.callXX calls methodValueCall, neither of which knows the
601
- // layout of the args. That's bad for precise gc & stack copying.
602
- y := (* methodValue )(fn )
603
- if y .fn == methodValueCallCode {
604
- _ , fn , rcvr = methodReceiver ("call" , y .rcvr , y .method )
605
- args = append (args , unsafe .Pointer (nil ))
606
- copy (args [1 :], args )
607
- args [0 ] = unsafe .Pointer (rcvr )
608
- ptr = unsafe .Pointer (& args [0 ])
609
- off += ptrSize
610
- size += ptrSize
611
- }
612
-
613
603
// Call.
614
- call (fn , ptr , uint32 (size ))
604
+ call (fn , args , uint32 (frametype . size ))
615
605
616
606
// Copy return values out of args.
617
- //
618
- // TODO(rsc): revisit like above.
619
607
ret := make ([]Value , nout )
620
608
for i := 0 ; i < nout ; i ++ {
621
609
tv := t .Out (i )
622
610
a := uintptr (tv .Align ())
623
611
off = (off + a - 1 ) &^ (a - 1 )
624
612
fl := flagIndir | flag (tv .Kind ())<< flagKindShift
625
- ret [i ] = Value {tv .common (), unsafe .Pointer (uintptr (ptr ) + off ), 0 , fl }
613
+ ret [i ] = Value {tv .common (), unsafe .Pointer (uintptr (args ) + off ), 0 , fl }
626
614
off += tv .Size ()
627
615
}
628
616
@@ -710,7 +698,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
710
698
// described by v. The Value v may or may not have the
711
699
// flagMethod bit set, so the kind cached in v.flag should
712
700
// not be used.
713
- func methodReceiver (op string , v Value , methodIndex int ) (t * rtype , fn unsafe.Pointer , rcvr iword ) {
701
+ // The return value t gives the method type signature (without the receiver).
702
+ // The return value fn is a pointer to the method code.
703
+ func methodReceiver (op string , v Value , methodIndex int ) (t * rtype , fn unsafe.Pointer ) {
714
704
i := methodIndex
715
705
if v .typ .Kind () == Interface {
716
706
tt := (* interfaceType )(unsafe .Pointer (v .typ ))
@@ -721,13 +711,12 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
721
711
if m .pkgPath != nil {
722
712
panic ("reflect: " + op + " of unexported method" )
723
713
}
724
- t = m .typ
725
714
iface := (* nonEmptyInterface )(v .ptr )
726
715
if iface .itab == nil {
727
716
panic ("reflect: " + op + " of method on nil interface value" )
728
717
}
729
718
fn = unsafe .Pointer (& iface .itab .fun [i ])
730
- rcvr = iface . word
719
+ t = m . typ
731
720
} else {
732
721
ut := v .typ .uncommon ()
733
722
if ut == nil || i < 0 || i >= len (ut .methods ) {
@@ -739,58 +728,41 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
739
728
}
740
729
fn = unsafe .Pointer (& m .ifn )
741
730
t = m .mtyp
742
- rcvr = v .iword ()
743
731
}
744
732
return
745
733
}
746
734
735
+ // v is a method receiver. Store at p the word which is used to
736
+ // encode that receiver at the start of the argument list.
737
+ // Reflect uses the "interface" calling convention for
738
+ // methods, which always uses one word to record the receiver.
739
+ func storeRcvr (v Value , p unsafe.Pointer ) {
740
+ t := v .typ
741
+ if t .Kind () == Interface {
742
+ // the interface data word becomes the receiver word
743
+ iface := (* nonEmptyInterface )(v .ptr )
744
+ * (* unsafe .Pointer )(p ) = unsafe .Pointer (iface .word )
745
+ } else if v .flag & flagIndir != 0 {
746
+ if t .size > ptrSize {
747
+ * (* unsafe .Pointer )(p ) = v .ptr
748
+ } else if t .pointers () {
749
+ * (* unsafe .Pointer )(p ) = * (* unsafe .Pointer )(v .ptr )
750
+ } else {
751
+ * (* uintptr )(p ) = loadScalar (v .ptr , t .size )
752
+ }
753
+ } else if t .pointers () {
754
+ * (* unsafe .Pointer )(p ) = v .ptr
755
+ } else {
756
+ * (* uintptr )(p ) = v .scalar
757
+ }
758
+ }
759
+
747
760
// align returns the result of rounding x up to a multiple of n.
748
761
// n must be a power of two.
749
762
func align (x , n uintptr ) uintptr {
750
763
return (x + n - 1 ) &^ (n - 1 )
751
764
}
752
765
753
- // frameSize returns the sizes of the argument and result frame
754
- // for a function of the given type. The rcvr bool specifies whether
755
- // a one-word receiver should be included in the total.
756
- func frameSize (t * rtype , rcvr bool ) (total , in , outOffset , out uintptr ) {
757
- if rcvr {
758
- // extra word for receiver interface word
759
- total += ptrSize
760
- }
761
-
762
- nin := t .NumIn ()
763
- in = - total
764
- for i := 0 ; i < nin ; i ++ {
765
- tv := t .In (i )
766
- total = align (total , uintptr (tv .Align ()))
767
- total += tv .Size ()
768
- }
769
- in += total
770
- total = align (total , ptrSize )
771
- nout := t .NumOut ()
772
- outOffset = total
773
- out = - total
774
- for i := 0 ; i < nout ; i ++ {
775
- tv := t .Out (i )
776
- total = align (total , uintptr (tv .Align ()))
777
- total += tv .Size ()
778
- }
779
- out += total
780
-
781
- // total must be > 0 in order for &args[0] to be valid.
782
- // the argument copying is going to round it up to
783
- // a multiple of ptrSize anyway, so make it ptrSize to begin with.
784
- if total < ptrSize {
785
- total = ptrSize
786
- }
787
-
788
- // round to pointer
789
- total = align (total , ptrSize )
790
-
791
- return
792
- }
793
-
794
766
// callMethod is the call implementation used by a function returned
795
767
// by makeMethodValue (used by v.Method(i).Interface()).
796
768
// It is a streamlined version of the usual reflect call: the caller has
@@ -803,24 +775,23 @@ func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
803
775
// so that the linker can make it work correctly for panic and recover.
804
776
// The gc compilers know to do that for the name "reflect.callMethod".
805
777
func callMethod (ctxt * methodValue , frame unsafe.Pointer ) {
806
- t , fn , rcvr := methodReceiver ("call" , ctxt .rcvr , ctxt .method )
807
- total , in , outOffset , out := frameSize (t , true )
808
-
809
- // Copy into args.
810
- //
811
- // TODO(rsc): This will need to be updated for any new garbage collector.
812
- // For now make everything look like a pointer by allocating
813
- // a []unsafe.Pointer.
814
- args := make ([]unsafe.Pointer , total / ptrSize )
815
- args [0 ] = unsafe .Pointer (rcvr )
816
- base := unsafe .Pointer (& args [0 ])
817
- memmove (unsafe .Pointer (uintptr (base )+ ptrSize ), frame , in )
778
+ rcvr := ctxt .rcvr
779
+ rcvrtype := rcvr .typ
780
+ t , fn := methodReceiver ("call" , rcvr , ctxt .method )
781
+ frametype := funcLayout (t , rcvrtype )
782
+
783
+ // Make a new frame that is one word bigger so we can store the receiver.
784
+ args := unsafe_New (frametype )
785
+
786
+ // Copy in receiver and rest of args.
787
+ storeRcvr (rcvr , args )
788
+ memmove (unsafe .Pointer (uintptr (args )+ ptrSize ), frame , frametype .size - ptrSize )
818
789
819
790
// Call.
820
- call (fn , unsafe . Pointer ( & args [ 0 ]) , uint32 (total ))
791
+ call (fn , args , uint32 (frametype . size ))
821
792
822
793
// Copy return values.
823
- memmove (unsafe . Pointer ( uintptr ( frame ) + outOffset - ptrSize ) , unsafe .Pointer (uintptr (base ) + outOffset ), out )
794
+ memmove (frame , unsafe .Pointer (uintptr (args ) + ptrSize ), frametype . size - ptrSize )
824
795
}
825
796
826
797
// funcName returns the name of f, for use in error messages.
0 commit comments