github.com/goplusjs/reflectx@v0.5.4/rtype_js.go (about) 1 //go:build js && !wasm 2 // +build js,!wasm 3 4 package reflectx 5 6 import ( 7 "reflect" 8 "unsafe" 9 10 "github.com/goplusjs/gopherjs/js" 11 ) 12 13 //go:linkname reflectType reflect.reflectType 14 func reflectType(typ *js.Object) *rtype 15 16 //go:linkname setKindType reflect.setKindType 17 func setKindType(rt *rtype, kindType interface{}) 18 19 //go:linkname newNameOff reflect.newNameOff 20 func newNameOff(n name) nameOff 21 22 //go:linkname newTypeOff reflect.newTypeOff 23 func newTypeOff(rt *rtype) typeOff 24 25 //go:linkname makeValue reflect.makeValue 26 func makeValue(t *rtype, v *js.Object, fl flag) reflect.Value 27 28 // func jsType(typ Type) *js.Object { 29 // return js.InternalObject(typ).Get("jsType") 30 // } 31 32 // func reflectType(typ *js.Object) *rtype { 33 // return _reflectType(typ, internalStr) 34 // } 35 36 func toStructType(t *rtype) *structType { 37 kind := js.InternalObject(t).Get("kindType") 38 return (*structType)(unsafe.Pointer(kind.Unsafe())) 39 } 40 41 func toKindType(t *rtype) unsafe.Pointer { 42 return unsafe.Pointer(js.InternalObject(t).Get("kindType").Unsafe()) 43 } 44 45 func toUncommonType(t *rtype) *uncommonType { 46 kind := js.InternalObject(t).Get("uncommonType") 47 if kind == js.Undefined { 48 return nil 49 } 50 return (*uncommonType)(unsafe.Pointer(kind.Unsafe())) 51 } 52 53 type uncommonType struct { 54 pkgPath nameOff 55 mcount uint16 56 xcount uint16 57 moff uint32 58 59 _methods []method 60 } 61 62 func (t *uncommonType) exportedMethods() []method { 63 if t.xcount == 0 { 64 return nil 65 } 66 return t._methods[:t.xcount:t.xcount] 67 } 68 69 func (t *uncommonType) methods() []method { 70 if t.mcount == 0 { 71 return nil 72 } 73 return t._methods 74 } 75 76 func (t *rtype) ptrTo() *rtype { 77 return reflectType(js.Global.Call("$ptrType", jsType(t))) 78 } 79 80 func (t *rtype) uncommon() *uncommonType { 81 return toUncommonType(t) 82 } 83 84 func (t *rtype) exportedMethods() []method { 85 ut := t.uncommon() 86 if ut == nil { 87 return nil 88 } 89 return ut.exportedMethods() 90 } 91 92 func (t *rtype) methods() []method { 93 ut := t.uncommon() 94 if ut == nil { 95 return nil 96 } 97 return ut._methods 98 } 99 100 func (t *rtype) IsVariadic() bool { 101 if t.Kind() != reflect.Func { 102 panic("reflect: IsVariadic of non-func type " + toType(t).String()) 103 } 104 tt := (*funcType)(unsafe.Pointer(t)) 105 return tt.outCount&(1<<15) != 0 106 } 107 108 /* 109 var $kindBool = 1; 110 var $kindInt = 2; 111 var $kindInt8 = 3; 112 var $kindInt16 = 4; 113 var $kindInt32 = 5; 114 var $kindInt64 = 6; 115 var $kindUint = 7; 116 var $kindUint8 = 8; 117 var $kindUint16 = 9; 118 var $kindUint32 = 10; 119 var $kindUint64 = 11; 120 var $kindUintptr = 12; 121 var $kindFloat32 = 13; 122 var $kindFloat64 = 14; 123 var $kindComplex64 = 15; 124 var $kindComplex128 = 16; 125 var $kindArray = 17; 126 var $kindChan = 18; 127 var $kindFunc = 19; 128 var $kindInterface = 20; 129 var $kindMap = 21; 130 var $kindPtr = 22; 131 var $kindSlice = 23; 132 var $kindString = 24; 133 var $kindStruct = 25; 134 var $kindUnsafePointer = 26; 135 136 var $Bool = $newType( 1, $kindBool, "bool", true, "", false, null); 137 var $Int = $newType( 4, $kindInt, "int", true, "", false, null); 138 var $Int8 = $newType( 1, $kindInt8, "int8", true, "", false, null); 139 var $Int16 = $newType( 2, $kindInt16, "int16", true, "", false, null); 140 var $Int32 = $newType( 4, $kindInt32, "int32", true, "", false, null); 141 var $Int64 = $newType( 8, $kindInt64, "int64", true, "", false, null); 142 var $Uint = $newType( 4, $kindUint, "uint", true, "", false, null); 143 var $Uint8 = $newType( 1, $kindUint8, "uint8", true, "", false, null); 144 var $Uint16 = $newType( 2, $kindUint16, "uint16", true, "", false, null); 145 var $Uint32 = $newType( 4, $kindUint32, "uint32", true, "", false, null); 146 var $Uint64 = $newType( 8, $kindUint64, "uint64", true, "", false, null); 147 var $Uintptr = $newType( 4, $kindUintptr, "uintptr", true, "", false, null); 148 var $Float32 = $newType( 4, $kindFloat32, "float32", true, "", false, null); 149 var $Float64 = $newType( 8, $kindFloat64, "float64", true, "", false, null); 150 var $Complex64 = $newType( 8, $kindComplex64, "complex64", true, "", false, null); 151 var $Complex128 = $newType(16, $kindComplex128, "complex128", true, "", false, null); 152 var $String = $newType( 8, $kindString, "string", true, "", false, null); 153 var $UnsafePointer = $newType( 4, $kindUnsafePointer, "unsafe.Pointer", true, "", false, null); 154 */ 155 //var $newType = function(size, kind, string, named, pkg, exported, constructor) { 156 157 var ( 158 fnNewType = js.Global.Get("$newType") 159 ) 160 161 /* 162 Invalid Kind = iota 163 Bool 164 Int 165 Int8 166 Int16 167 Int32 168 Int64 169 Uint 170 Uint8 171 Uint16 172 Uint32 173 Uint64 174 Uintptr 175 Float32 176 Float64 177 Complex64 178 Complex128 179 Array 180 Chan 181 Func 182 Interface 183 Map 184 Ptr 185 Slice 186 String 187 Struct 188 UnsafePointer 189 */ 190 var ( 191 sizes = []int{0, 1, 192 4, 1, 2, 4, 8, // int 193 4, 1, 2, 4, 8, // uint 194 4, // uintptr 195 4, 8, // float 196 8, 16, // complex 197 4, // array 198 4, // 199 4, 200 4, 201 4, 202 4, 203 12, // slice 204 8, // string 205 4, // struct 206 4, // UnsafePointer 207 } 208 ) 209 210 func tovalue(v *reflect.Value) *Value { 211 return (*Value)(unsafe.Pointer(v)) 212 } 213 214 func toValue(v Value) reflect.Value { 215 return *(*reflect.Value)(unsafe.Pointer(&v)) 216 } 217 218 func NamedTypeOf(pkg string, name string, from reflect.Type) (typ reflect.Type) { 219 rt, _ := newType(pkg, name, from, 0, 0) 220 setTypeName(rt, pkg, name) 221 typ = toType(rt) 222 nt := &Named{Name: name, PkgPath: pkg, Type: typ, From: from, Kind: TkType} 223 ntypeMap[typ] = nt 224 return 225 } 226 227 var ( 228 jsUncommonTyp = js.InternalObject(reflect.TypeOf((*rtype)(nil))).Get("uncommonType").Get("constructor") 229 ) 230 231 func resetUncommonType(rt *rtype, mcount int, xcount int) *uncommonType { 232 ut := jsUncommonTyp.New() 233 v := js.InternalObject(ut).Get("_methods").Get("constructor") 234 ut.Set("xcount", xcount) 235 ut.Set("mcount", mcount) 236 ut.Set("_methods", js.Global.Call("$makeSlice", v, mcount, mcount)) 237 ut.Set("jsType", jsType(rt)) 238 js.InternalObject(rt).Set("uncommonType", ut) 239 return (*uncommonType)(unsafe.Pointer(ut.Unsafe())) 240 } 241 242 func newType(pkg string, name string, styp reflect.Type, xcount int, mcount int) (*rtype, []method) { 243 kind := styp.Kind() 244 var obj *js.Object 245 switch kind { 246 default: 247 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 248 case reflect.Array: 249 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 250 obj.Call("init", jsType(styp.Elem()), styp.Len()) 251 case reflect.Slice: 252 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 253 obj.Call("init", jsType(styp.Elem())) 254 case reflect.Map: 255 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 256 obj.Call("init", jsType(styp.Key()), jsType(styp.Elem())) 257 case reflect.Ptr: 258 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 259 obj.Call("init", jsType(styp.Elem())) 260 case reflect.Chan: 261 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 262 obj.Call("init", jsType(styp.Elem())) 263 case reflect.Func: 264 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 265 obj.Call("init", jsType(styp).Get("params"), jsType(styp).Get("results"), styp.IsVariadic()) 266 case reflect.Interface: 267 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 268 obj.Call("init", jsType(styp).Get("methods")) 269 case reflect.Struct: 270 fields := js.Global.Get("Array").New() 271 for i := 0; i < styp.NumField(); i++ { 272 sf := styp.Field(i) 273 jsf := js.Global.Get("Object").New() 274 jsf.Set("prop", sf.Name) 275 jsf.Set("name", sf.Name) 276 jsf.Set("exported", true) 277 jsf.Set("typ", jsType(sf.Type)) 278 jsf.Set("tag", sf.Tag) 279 jsf.Set("embedded", sf.Anonymous) 280 fields.SetIndex(i, jsf) 281 } 282 fn := js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 283 this.Set("$val", this) 284 for i := 0; i < fields.Length(); i++ { 285 f := fields.Index(i) 286 if len(args) > i && args[i] != js.Undefined { 287 this.Set(f.Get("prop").String(), args[i]) 288 } else { 289 this.Set(f.Get("prop").String(), f.Get("typ").Call("zero")) 290 } 291 } 292 return nil 293 }) 294 obj = fnNewType.Invoke(styp.Size(), kind, styp.Name(), false, pkg, false, fn) 295 obj.Call("init", pkg, fields) 296 } 297 rt := reflectType(obj) 298 if kind == reflect.Func || kind == reflect.Interface { 299 return rt, nil 300 } 301 rt.tflag |= tflagUncommon 302 ut := resetUncommonType(rt, xcount, mcount) 303 return rt, ut._methods 304 } 305 306 func totype(typ reflect.Type) *rtype { 307 v := reflect.Zero(typ) 308 rt := (*Value)(unsafe.Pointer(&v)).typ 309 return rt 310 } 311 312 // emptyInterface is the header for an interface{} value. 313 // type emptyInterface struct { 314 // typ *rtype 315 // word unsafe.Pointer 316 // } 317 318 // func totype(typ reflect.Type) *rtype { 319 // e := (*emptyInterface)(unsafe.Pointer(&typ)) 320 // return (*rtype)(e.word) 321 // } 322 323 func internalStr(strObj *js.Object) string { 324 var c struct{ str string } 325 js.InternalObject(c).Set("str", strObj) // get string without internalizing 326 return c.str 327 } 328 329 type funcType struct { 330 rtype `reflect:"func"` 331 inCount uint16 332 outCount uint16 333 334 _in []*rtype 335 _out []*rtype 336 } 337 338 func (t *funcType) in() []*rtype { 339 return t._in 340 } 341 342 func (t *funcType) out() []*rtype { 343 return t._out 344 } 345 346 func jsType(typ interface{}) *js.Object { 347 return js.InternalObject(typ).Get("jsType") 348 } 349 350 func NumMethodX(typ reflect.Type) int { 351 t := totype(typ) 352 ut := t.uncommon() 353 if ut == nil { 354 return 0 355 } 356 return len(ut.methods()) 357 } 358 359 func MethodX(typ reflect.Type, i int) (m reflect.Method) { 360 if typ.Kind() == reflect.Interface { 361 return typ.Method(i) 362 } 363 t := totype(typ) 364 ut := t.uncommon() 365 methods := ut.methods() 366 if i < 0 || i >= len(methods) { 367 panic("reflect: Method index out of range") 368 } 369 p := methods[i] 370 pname := t.nameOff(p.name) 371 m.Name = pname.name() 372 fl := flag(reflect.Func) 373 mtyp := t.typeOff(p.mtyp) 374 ft := (*funcType)(toKindType(mtyp)) 375 in := make([]reflect.Type, 0, 1+len(ft.in())) 376 in = append(in, toType(t)) 377 for _, arg := range ft.in() { 378 in = append(in, toType(arg)) 379 } 380 out := make([]reflect.Type, 0, len(ft.out())) 381 for _, ret := range ft.out() { 382 out = append(out, toType(ret)) 383 } 384 mt := reflect.FuncOf(in, out, ft.IsVariadic()) 385 m.Type = mt 386 prop := js.Global.Call("$methodSet", js.InternalObject(t).Get("jsType")).Index(i).Get("prop").String() 387 fn := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { 388 rcvr := arguments[0] 389 return rcvr.Get(prop).Call("apply", rcvr, arguments[1:]) 390 }) 391 m.Func = toValue(Value{totype(mt), unsafe.Pointer(fn.Unsafe()), fl}) 392 m.Index = i 393 return m 394 } 395 396 func MethodByNameX(typ reflect.Type, name string) (m reflect.Method, ok bool) { 397 if typ.Kind() == reflect.Interface { 398 return typ.MethodByName(name) 399 } 400 t := totype(typ) 401 ut := t.uncommon() 402 if ut == nil { 403 return reflect.Method{}, false 404 } 405 for i, p := range ut.methods() { 406 if t.nameOff(p.name).name() == name { 407 return MethodX(typ, i), true 408 } 409 } 410 return reflect.Method{}, false 411 } 412 413 // Field returns the i'th field of the struct v. 414 // It panics if v's Kind is not Struct or i is out of range. 415 func FieldX(v reflect.Value, i int) reflect.Value { 416 field := v.Field(i) 417 canSet(&field) 418 return field 419 } 420 421 func SetUnderlying(typ reflect.Type, styp reflect.Type) { 422 rt := totype(typ) 423 ort := totype(styp) 424 switch styp.Kind() { 425 case reflect.Struct: 426 st := (*structType)(toKindType(rt)) 427 ost := (*structType)(toKindType(ort)) 428 st.fields = ost.fields 429 case reflect.Ptr: 430 st := (*ptrType)(toKindType(rt)) 431 ost := (*ptrType)(toKindType(ort)) 432 st.elem = ost.elem 433 case reflect.Slice: 434 st := (*sliceType)(toKindType(rt)) 435 ost := (*sliceType)(toKindType(ort)) 436 st.elem = ost.elem 437 case reflect.Array: 438 st := (*arrayType)(toKindType(rt)) 439 ost := (*arrayType)(toKindType(ort)) 440 st.elem = ost.elem 441 st.slice = ost.slice 442 st.len = ost.len 443 case reflect.Chan: 444 st := (*chanType)(toKindType(rt)) 445 ost := (*chanType)(toKindType(ort)) 446 st.elem = ost.elem 447 st.dir = ost.dir 448 case reflect.Interface: 449 st := (*interfaceType)(toKindType(rt)) 450 ost := (*interfaceType)(toKindType(ort)) 451 st.methods = ost.methods 452 case reflect.Map: 453 st := (*mapType)(toKindType(rt)) 454 ost := (*mapType)(toKindType(ort)) 455 st.key = ost.key 456 st.elem = ost.elem 457 st.bucket = ost.bucket 458 st.hasher = ost.hasher 459 st.keysize = ost.keysize 460 st.valuesize = ost.valuesize 461 st.bucketsize = ost.bucketsize 462 st.flags = ost.flags 463 case reflect.Func: 464 st := (*funcType)(toKindType(rt)) 465 ost := (*funcType)(toKindType(ort)) 466 st.inCount = ost.inCount 467 st.outCount = ost.outCount 468 st._in = ost._in 469 st._out = ost._out 470 } 471 rt.size = ort.size 472 rt.tflag |= tflagUncommon | tflagExtraStar | tflagNamed 473 rt.kind = ort.kind 474 rt.align = ort.align 475 rt.fieldAlign = ort.fieldAlign 476 rt.gcdata = ort.gcdata 477 rt.ptrdata = ort.ptrdata 478 rt.equal = ort.equal 479 //rt.str = resolveReflectName(ort.nameOff(ort.str)) 480 if isRegularMemory(typ) { 481 rt.tflag |= tflagRegularMemory 482 } 483 }