Skip to content

Commit 203c1d0

Browse files
Working on reflect
1 parent 4578fba commit 203c1d0

File tree

6 files changed

+102
-59
lines changed

6 files changed

+102
-59
lines changed

compiler/natives/src/internal/abi/type.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ func (t *Type) setUncommon(ut *UncommonType) {
3030
js.InternalObject(t).Set(idUncommonType, js.InternalObject(ut))
3131
}
3232

33+
//gopherjs:add This is the same as ArrayType(), MapType(), etc but they didn't have one for ChanType.
34+
func (t *Type) ChanType() *ChanType {
35+
if t.Kind() != Chan {
36+
return nil
37+
}
38+
return (*ChanType)(unsafe.Pointer(t))
39+
}
40+
3341
//gopherjs:replace
3442
type UncommonType struct {
3543
PkgPath NameOff // import path

compiler/natives/src/internal/reflectlite/value.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ func valueInterface(v Value) any {
6868
return any(unsafe.Pointer(v.object().Unsafe()))
6969
}
7070

71-
//gopherjs:new This is new but there are commented out references in the original code.
71+
//gopherjs:new This is new to reflectlite but there are commented out references in the native code and a copy in reflect.
7272
func makeMethodValue(op string, v Value) Value {
7373
if v.flag&flagMethod == 0 {
7474
panic("reflect: internal error: invalid use of makePartialFunc")
7575
}
7676

77-
_, _, fn := methodReceiver(op, v, int(v.flag)>>flagMethodShift)
77+
fn := methodReceiver(op, v, int(v.flag)>>flagMethodShift)
7878
rcvr := v.object()
7979
if v.typ.IsWrapped() {
8080
rcvr = v.typ.JsType().New(rcvr)
@@ -89,8 +89,8 @@ func makeMethodValue(op string, v Value) Value {
8989
}
9090
}
9191

92-
//gopherjs:new
93-
func methodReceiver(op string, v Value, i int) (_ rtype, t *funcType, fn unsafe.Pointer) {
92+
//gopherjs:new This is a simplified copy of the version in reflect.
93+
func methodReceiver(op string, v Value, i int) (fn unsafe.Pointer) {
9494
var prop string
9595
if v.typ.Kind() == abi.Interface {
9696
tt := v.typ.InterfaceType()
@@ -101,7 +101,6 @@ func methodReceiver(op string, v Value, i int) (_ rtype, t *funcType, fn unsafe.
101101
if !tt.NameOff(m.Name).IsExported() {
102102
panic("reflect: " + op + " of unexported method")
103103
}
104-
t = tt.TypeOff(m.Typ).FuncType()
105104
prop = tt.NameOff(m.Name).Name()
106105
} else {
107106
ms := v.typ.ExportedMethods()
@@ -112,7 +111,6 @@ func methodReceiver(op string, v Value, i int) (_ rtype, t *funcType, fn unsafe.
112111
if !v.typ.NameOff(m.Name).IsExported() {
113112
panic("reflect: " + op + " of unexported method")
114113
}
115-
t = v.typ.TypeOff(m.Mtyp).FuncType()
116114
prop = js.Global.Call("$methodSet", v.typ.JsType()).Index(i).Get("prop").String()
117115
}
118116
rcvr := v.object()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//go:build js
2+
3+
package reflect
4+
5+
import (
6+
"unsafe"
7+
8+
"github.com/gopherjs/gopherjs/js"
9+
)
10+
11+
func makeMethodValue(op string, v Value) Value {
12+
if v.flag&flagMethod == 0 {
13+
panic("reflect: internal error: invalid use of makePartialFunc")
14+
}
15+
16+
_, _, fn := methodReceiver(op, v, int(v.flag)>>flagMethodShift)
17+
rcvr := v.object()
18+
if isWrapped(v.typ) {
19+
rcvr = jsType(v.typ).New(rcvr)
20+
}
21+
fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) any {
22+
return js.InternalObject(fn).Call("apply", rcvr, arguments)
23+
})
24+
return Value{v.Type().common(), unsafe.Pointer(fv.Unsafe()), v.flag.ro() | flag(Func)}
25+
}

compiler/natives/src/reflect/reflect.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -142,22 +142,6 @@ func valueInterface(v Value, safe bool) any {
142142
return any(unsafe.Pointer(v.object().Unsafe()))
143143
}
144144

145-
func makeMethodValue(op string, v Value) Value {
146-
if v.flag&flagMethod == 0 {
147-
panic("reflect: internal error: invalid use of makePartialFunc")
148-
}
149-
150-
_, _, fn := methodReceiver(op, v, int(v.flag)>>flagMethodShift)
151-
rcvr := v.object()
152-
if isWrapped(v.typ) {
153-
rcvr = jsType(v.typ).New(rcvr)
154-
}
155-
fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) any {
156-
return js.InternalObject(fn).Call("apply", rcvr, arguments)
157-
})
158-
return Value{v.Type().common(), unsafe.Pointer(fv.Unsafe()), v.flag.ro() | flag(Func)}
159-
}
160-
161145
func (t *rtype) pointers() bool {
162146
switch t.Kind() {
163147
case Ptr, Map, Chan, Func, Struct, Array:

compiler/natives/src/reflect/type.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ func init() {
3434
uint8Type = TypeOf(uint8(0)).(*rtype) // set for real
3535
}
3636

37-
//gopherjd:replace
38-
func pkgPath(n abi.Name) string {
39-
return n.PkgPath()
40-
}
41-
4237
//gopherjs:new
4338
func toAbiType(typ Type) *abi.Type {
4439
return typ.(*rtype).common()
@@ -86,6 +81,11 @@ func resolveReflectText(ptr unsafe.Pointer) aTextOff {
8681
return abi.ResolveReflectText(ptr)
8782
}
8883

84+
//gopherjd:replace
85+
func pkgPath(n abi.Name) string {
86+
return n.PkgPath()
87+
}
88+
8989
func TypeOf(i any) Type {
9090
if !initialized { // avoid error of uint8Type
9191
return &rtype{}

compiler/natives/src/reflect/value.go

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212
"github.com/gopherjs/gopherjs/js"
1313
)
1414

15+
//gopherjs:purge This is the header for an interface value with methods and not needed for GopherJS.
16+
type nonEmptyInterface struct{}
17+
1518
// New returns a Value representing a pointer to a new zero value
1619
// for the specified type. That is, the returned Value's Type is PtrTo(typ).
1720
//
@@ -24,11 +27,11 @@ func New(typ Type) Value {
2427
if typ == nil {
2528
panic("reflect: New(nil)")
2629
}
27-
t := typ.(*rtype)
28-
pt := t.ptrTo()
30+
t := toAbiType(typ)
31+
pt := t.PtrTo()
2932
ptr := unsafe_New(t)
3033
fl := flag(Pointer)
31-
return Value{typ: pt, ptr: ptr, flag: fl}
34+
return Value{typ_: pt, ptr: ptr, flag: fl}
3235
}
3336

3437
//gopherjs:replace
@@ -44,12 +47,20 @@ func unsafe_New(typ *abi.Type) unsafe.Pointer {
4447
return abi.UnsafeNew(typ)
4548
}
4649

47-
func makeValue(t Type, v *js.Object, fl flag) Value {
48-
rt := t.common()
49-
if t.Kind() == Array || t.Kind() == Struct || t.Kind() == Ptr {
50-
return Value{rt, unsafe.Pointer(v.Unsafe()), fl | flag(t.Kind())}
50+
func makeValue(t *abi.Type, v *js.Object, fl flag) Value {
51+
switch t.Kind() {
52+
case abi.Array, abi.Struct, abi.Pointer:
53+
return Value{
54+
typ_: t,
55+
ptr: unsafe.Pointer(v.Unsafe()),
56+
flag: fl | flag(t.Kind()),
57+
}
58+
}
59+
return Value{
60+
typ_: t,
61+
ptr: unsafe.Pointer(js.Global.Call("$newDataPointer", v, t.JsPtrTo()).Unsafe()),
62+
flag: fl | flag(t.Kind()) | flagIndir,
5163
}
52-
return Value{rt, unsafe.Pointer(js.Global.Call("$newDataPointer", v, jsType(rt.ptrTo())).Unsafe()), fl | flag(t.Kind()) | flagIndir}
5364
}
5465

5566
func MakeSlice(typ Type, len, cap int) Value {
@@ -66,74 +77,91 @@ func MakeSlice(typ Type, len, cap int) Value {
6677
panic("reflect.MakeSlice: len > cap")
6778
}
6879

69-
return makeValue(typ, js.Global.Call("$makeSlice", jsType(typ), len, cap, js.InternalObject(func() *js.Object { return jsType(typ.Elem()).Call("zero") })), 0)
80+
return makeValue(toAbiType(typ), js.Global.Call("$makeSlice", jsType(typ), len, cap, js.InternalObject(func() *js.Object { return jsType(typ.Elem()).Call("zero") })), 0)
7081
}
7182

7283
func Zero(typ Type) Value {
73-
return makeValue(typ, jsType(typ).Call("zero"), 0)
84+
return makeValue(toAbiType(typ), jsType(typ).Call("zero"), 0)
7485
}
7586

7687
func makeInt(f flag, bits uint64, t Type) Value {
7788
typ := t.common()
7889
ptr := unsafe_New(typ)
7990
switch typ.Kind() {
80-
case Int8:
91+
case abi.Int8:
8192
*(*int8)(ptr) = int8(bits)
82-
case Int16:
93+
case abi.Int16:
8394
*(*int16)(ptr) = int16(bits)
84-
case Int, Int32:
95+
case abi.Int, abi.Int32:
8596
*(*int32)(ptr) = int32(bits)
86-
case Int64:
97+
case abi.Int64:
8798
*(*int64)(ptr) = int64(bits)
88-
case Uint8:
99+
case abi.Uint8:
89100
*(*uint8)(ptr) = uint8(bits)
90-
case Uint16:
101+
case abi.Uint16:
91102
*(*uint16)(ptr) = uint16(bits)
92-
case Uint, Uint32, Uintptr:
103+
case abi.Uint, abi.Uint32, abi.Uintptr:
93104
*(*uint32)(ptr) = uint32(bits)
94-
case Uint64:
105+
case abi.Uint64:
95106
*(*uint64)(ptr) = uint64(bits)
96107
}
97-
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
108+
return Value{
109+
typ_: typ,
110+
ptr: ptr,
111+
flag: f | flagIndir | flag(typ.Kind()),
112+
}
98113
}
99114

100115
//gopherjs:replace
101116
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *abi.Type, t *funcType, fn unsafe.Pointer) {
102117
i := methodIndex
103118
var prop string
104-
if v.typ.Kind() == Interface {
105-
tt := (*interfaceType)(unsafe.Pointer(v.typ))
106-
if i < 0 || i >= len(tt.methods) {
119+
if tt := v.typ().InterfaceType(); tt != nil {
120+
if i < 0 || i >= len(tt.Methods) {
107121
panic("reflect: internal error: invalid method index")
108122
}
109-
m := &tt.methods[i]
110-
if !tt.nameOff(m.name).isExported() {
123+
m := &tt.Methods[i]
124+
if !tt.NameOff(m.Name).IsExported() {
111125
panic("reflect: " + op + " of unexported method")
112126
}
113-
rcvrtype = iface.itab.typ
114-
t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
115-
prop = tt.nameOff(m.name).name()
127+
// TODO(grantnelson-wf): Set rcvrtype to the type the interface is holding onto.
128+
t = tt.TypeOff(m.typ).FuncType()
129+
prop = tt.NameOff(m.Name).Name()
116130
} else {
117131
rcvrtype = v.typ()
118-
ms := v.typ.exportedMethods()
132+
ms := v.typ().ExportedMethods()
119133
if uint(i) >= uint(len(ms)) {
120134
panic("reflect: internal error: invalid method index")
121135
}
122136
m := ms[i]
123-
if !v.typ.nameOff(m.name).isExported() {
137+
if !v.typ().NameOff(m.Name).IsExported() {
124138
panic("reflect: " + op + " of unexported method")
125139
}
126-
t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
140+
t = v.typ().TypeOff(m.mtyp).FuncType()
127141
prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
128142
}
129143
rcvr := v.object()
130-
if isWrapped(v.typ) {
144+
if v.typ().IsWrapped() {
131145
rcvr = jsType(v.typ).New(rcvr)
132146
}
133147
fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
134148
return
135149
}
136150

151+
//gopherjs:replace
152+
func storeRcvr(v Value, p unsafe.Pointer) {
153+
t := v.typ()
154+
if t.Kind() == abi.Interface {
155+
// the interface data word becomes the receiver word
156+
iface := (*nonEmptyInterface)(v.ptr)
157+
*(*unsafe.Pointer)(p) = iface.word
158+
} else if v.flag&flagIndir != 0 && !ifaceIndir(t) {
159+
*(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
160+
} else {
161+
*(*unsafe.Pointer)(p) = v.ptr
162+
}
163+
}
164+
137165
func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
138166
if typ.Kind() != Func {
139167
panic("reflect: call of MakeFunc with non-Func type")
@@ -193,7 +221,7 @@ func typedmemmove(t *abi.Type, dst, src unsafe.Pointer) {
193221

194222
//gopherjs:replace
195223
func makechan(typ *abi.Type, size int) (ch unsafe.Pointer) {
196-
ctyp := (*abi.ChanType)(unsafe.Pointer(typ))
224+
ctyp := typ.ChanType()
197225
return unsafe.Pointer(js.Global.Get("$Chan").New(jsType(ctyp.Elem), size).Unsafe())
198226
}
199227

0 commit comments

Comments
 (0)