1// +build js 2// +build go1.11.1 3 4package reflect 5 6import ( 7 "unsafe" 8 9 "github.com/gopherjs/gopherjs/js" 10) 11 12func methodReceiver(op string, v Value, i int) (_ *rtype, t *funcType, fn unsafe.Pointer) { 13 var prop string 14 if v.typ.Kind() == Interface { 15 tt := (*interfaceType)(unsafe.Pointer(v.typ)) 16 if i < 0 || i >= len(tt.methods) { 17 panic("reflect: internal error: invalid method index") 18 } 19 m := &tt.methods[i] 20 if !tt.nameOff(m.name).isExported() { 21 panic("reflect: " + op + " of unexported method") 22 } 23 t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ))) 24 prop = tt.nameOff(m.name).name() 25 } else { 26 ms := v.typ.exportedMethods() 27 if uint(i) >= uint(len(ms)) { 28 panic("reflect: internal error: invalid method index") 29 } 30 m := ms[i] 31 if !v.typ.nameOff(m.name).isExported() { 32 panic("reflect: " + op + " of unexported method") 33 } 34 t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp))) 35 prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String() 36 } 37 rcvr := v.object() 38 if isWrapped(v.typ) { 39 rcvr = jsType(v.typ).New(rcvr) 40 } 41 fn = unsafe.Pointer(rcvr.Get(prop).Unsafe()) 42 return 43} 44 45func (v Value) call(op string, in []Value) []Value { 46 var ( 47 t *funcType 48 fn unsafe.Pointer 49 rcvr *js.Object 50 ) 51 if v.flag&flagMethod != 0 { 52 _, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) 53 rcvr = v.object() 54 if isWrapped(v.typ) { 55 rcvr = jsType(v.typ).New(rcvr) 56 } 57 } else { 58 t = (*funcType)(unsafe.Pointer(v.typ)) 59 fn = unsafe.Pointer(v.object().Unsafe()) 60 rcvr = js.Undefined 61 } 62 63 if fn == nil { 64 panic("reflect.Value.Call: call of nil function") 65 } 66 67 isSlice := op == "CallSlice" 68 n := t.NumIn() 69 if isSlice { 70 if !t.IsVariadic() { 71 panic("reflect: CallSlice of non-variadic function") 72 } 73 if len(in) < n { 74 panic("reflect: CallSlice with too few input arguments") 75 } 76 if len(in) > n { 77 panic("reflect: CallSlice with too many input arguments") 78 } 79 } else { 80 if t.IsVariadic() { 81 n-- 82 } 83 if len(in) < n { 84 panic("reflect: Call with too few input arguments") 85 } 86 if !t.IsVariadic() && len(in) > n { 87 panic("reflect: Call with too many input arguments") 88 } 89 } 90 for _, x := range in { 91 if x.Kind() == Invalid { 92 panic("reflect: " + op + " using zero Value argument") 93 } 94 } 95 for i := 0; i < n; i++ { 96 if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) { 97 panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String()) 98 } 99 } 100 if !isSlice && t.IsVariadic() { 101 // prepare slice for remaining values 102 m := len(in) - n 103 slice := MakeSlice(t.In(n), m, m) 104 elem := t.In(n).Elem() 105 for i := 0; i < m; i++ { 106 x := in[n+i] 107 if xt := x.Type(); !xt.AssignableTo(elem) { 108 panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op) 109 } 110 slice.Index(i).Set(x) 111 } 112 origIn := in 113 in = make([]Value, n+1) 114 copy(in[:n], origIn) 115 in[n] = slice 116 } 117 118 nin := len(in) 119 if nin != t.NumIn() { 120 panic("reflect.Value.Call: wrong argument count") 121 } 122 nout := t.NumOut() 123 124 argsArray := js.Global.Get("Array").New(t.NumIn()) 125 for i, arg := range in { 126 argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object())) 127 } 128 results := callHelper(js.InternalObject(fn), rcvr, argsArray) 129 130 switch nout { 131 case 0: 132 return nil 133 case 1: 134 return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)} 135 default: 136 ret := make([]Value, nout) 137 for i := range ret { 138 ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0) 139 } 140 return ret 141 } 142} 143