github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/natives/src/internal/reflectlite/reflectlite.go (about) 1 // +build js 2 3 package reflectlite 4 5 import ( 6 "unsafe" 7 8 "github.com/gopherjs/gopherjs/js" 9 ) 10 11 var initialized = false 12 13 func init() { 14 // avoid dead code elimination 15 used := func(i interface{}) {} 16 used(rtype{}) 17 used(uncommonType{}) 18 used(method{}) 19 used(arrayType{}) 20 used(chanType{}) 21 used(funcType{}) 22 used(interfaceType{}) 23 used(mapType{}) 24 used(ptrType{}) 25 used(sliceType{}) 26 used(structType{}) 27 used(imethod{}) 28 used(structField{}) 29 30 initialized = true 31 uint8Type = TypeOf(uint8(0)).(*rtype) // set for real 32 } 33 34 var ( 35 uint8Type *rtype 36 ) 37 38 var ( 39 idJsType = "_jsType" 40 idReflectType = "_reflectType" 41 idKindType = "kindType" 42 idRtype = "_rtype" 43 ) 44 45 func jsType(typ Type) *js.Object { 46 return js.InternalObject(typ).Get(idJsType) 47 } 48 49 func reflectType(typ *js.Object) *rtype { 50 if typ.Get(idReflectType) == js.Undefined { 51 rt := &rtype{ 52 size: uintptr(typ.Get("size").Int()), 53 kind: uint8(typ.Get("kind").Int()), 54 str: newNameOff(newName(internalStr(typ.Get("string")), "", typ.Get("exported").Bool())), 55 } 56 js.InternalObject(rt).Set(idJsType, typ) 57 typ.Set(idReflectType, js.InternalObject(rt)) 58 59 methodSet := js.Global.Call("$methodSet", typ) 60 if methodSet.Length() != 0 || typ.Get("named").Bool() { 61 rt.tflag |= tflagUncommon 62 if typ.Get("named").Bool() { 63 rt.tflag |= tflagNamed 64 } 65 var reflectMethods []method 66 for i := 0; i < methodSet.Length(); i++ { // Exported methods first. 67 m := methodSet.Index(i) 68 exported := internalStr(m.Get("pkg")) == "" 69 if !exported { 70 continue 71 } 72 reflectMethods = append(reflectMethods, method{ 73 name: newNameOff(newName(internalStr(m.Get("name")), "", exported)), 74 mtyp: newTypeOff(reflectType(m.Get("typ"))), 75 }) 76 } 77 xcount := uint16(len(reflectMethods)) 78 for i := 0; i < methodSet.Length(); i++ { // Unexported methods second. 79 m := methodSet.Index(i) 80 exported := internalStr(m.Get("pkg")) == "" 81 if exported { 82 continue 83 } 84 reflectMethods = append(reflectMethods, method{ 85 name: newNameOff(newName(internalStr(m.Get("name")), "", exported)), 86 mtyp: newTypeOff(reflectType(m.Get("typ"))), 87 }) 88 } 89 ut := &uncommonType{ 90 pkgPath: newNameOff(newName(internalStr(typ.Get("pkg")), "", false)), 91 mcount: uint16(methodSet.Length()), 92 xcount: xcount, 93 _methods: reflectMethods, 94 } 95 uncommonTypeMap[rt] = ut 96 js.InternalObject(ut).Set(idJsType, typ) 97 } 98 99 switch rt.Kind() { 100 case Array: 101 setKindType(rt, &arrayType{ 102 elem: reflectType(typ.Get("elem")), 103 len: uintptr(typ.Get("len").Int()), 104 }) 105 case Chan: 106 dir := BothDir 107 if typ.Get("sendOnly").Bool() { 108 dir = SendDir 109 } 110 if typ.Get("recvOnly").Bool() { 111 dir = RecvDir 112 } 113 setKindType(rt, &chanType{ 114 elem: reflectType(typ.Get("elem")), 115 dir: uintptr(dir), 116 }) 117 case Func: 118 params := typ.Get("params") 119 in := make([]*rtype, params.Length()) 120 for i := range in { 121 in[i] = reflectType(params.Index(i)) 122 } 123 results := typ.Get("results") 124 out := make([]*rtype, results.Length()) 125 for i := range out { 126 out[i] = reflectType(results.Index(i)) 127 } 128 outCount := uint16(results.Length()) 129 if typ.Get("variadic").Bool() { 130 outCount |= 1 << 15 131 } 132 setKindType(rt, &funcType{ 133 rtype: *rt, 134 inCount: uint16(params.Length()), 135 outCount: outCount, 136 _in: in, 137 _out: out, 138 }) 139 case Interface: 140 methods := typ.Get("methods") 141 imethods := make([]imethod, methods.Length()) 142 for i := range imethods { 143 m := methods.Index(i) 144 imethods[i] = imethod{ 145 name: newNameOff(newName(internalStr(m.Get("name")), "", internalStr(m.Get("pkg")) == "")), 146 typ: newTypeOff(reflectType(m.Get("typ"))), 147 } 148 } 149 setKindType(rt, &interfaceType{ 150 rtype: *rt, 151 pkgPath: newName(internalStr(typ.Get("pkg")), "", false), 152 methods: imethods, 153 }) 154 case Map: 155 setKindType(rt, &mapType{ 156 key: reflectType(typ.Get("key")), 157 elem: reflectType(typ.Get("elem")), 158 }) 159 case Ptr: 160 // p := (*ptrType)(unsafe.Pointer(rt)) 161 // p.elem = reflectType(typ.Get("elem")) 162 setKindType(rt, &ptrType{ 163 elem: reflectType(typ.Get("elem")), 164 }) 165 case Slice: 166 setKindType(rt, &sliceType{ 167 elem: reflectType(typ.Get("elem")), 168 }) 169 case Struct: 170 fields := typ.Get("fields") 171 reflectFields := make([]structField, fields.Length()) 172 for i := range reflectFields { 173 f := fields.Index(i) 174 offsetEmbed := uintptr(i) << 1 175 if f.Get("embedded").Bool() { 176 offsetEmbed |= 1 177 } 178 reflectFields[i] = structField{ 179 name: newName(internalStr(f.Get("name")), internalStr(f.Get("tag")), f.Get("exported").Bool()), 180 typ: reflectType(f.Get("typ")), 181 offsetEmbed: offsetEmbed, 182 } 183 } 184 setKindType(rt, &structType{ 185 rtype: *rt, 186 pkgPath: newName(internalStr(typ.Get("pkgPath")), "", false), 187 fields: reflectFields, 188 }) 189 } 190 } 191 192 return (*rtype)(unsafe.Pointer(typ.Get(idReflectType).Unsafe())) 193 } 194 195 func setKindType(rt *rtype, kindType interface{}) { 196 js.InternalObject(rt).Set(idKindType, js.InternalObject(kindType)) 197 js.InternalObject(kindType).Set(idRtype, js.InternalObject(rt)) 198 } 199 200 type uncommonType struct { 201 pkgPath nameOff 202 mcount uint16 203 xcount uint16 204 moff uint32 205 206 _methods []method 207 } 208 209 func (t *uncommonType) methods() []method { 210 return t._methods 211 } 212 213 func (t *uncommonType) exportedMethods() []method { 214 return t._methods[:t.xcount:t.xcount] 215 } 216 217 var uncommonTypeMap = make(map[*rtype]*uncommonType) 218 219 func (t *rtype) uncommon() *uncommonType { 220 return uncommonTypeMap[t] 221 } 222 223 type funcType struct { 224 rtype `reflect:"func"` 225 inCount uint16 226 outCount uint16 227 228 _in []*rtype 229 _out []*rtype 230 } 231 232 func (t *funcType) in() []*rtype { 233 return t._in 234 } 235 236 func (t *funcType) out() []*rtype { 237 return t._out 238 } 239 240 type name struct { 241 bytes *byte 242 } 243 244 type nameData struct { 245 name string 246 tag string 247 exported bool 248 } 249 250 var nameMap = make(map[*byte]*nameData) 251 252 func (n name) name() (s string) { return nameMap[n.bytes].name } 253 func (n name) tag() (s string) { return nameMap[n.bytes].tag } 254 func (n name) pkgPath() string { return "" } 255 func (n name) isExported() bool { return nameMap[n.bytes].exported } 256 257 func newName(n, tag string, exported bool) name { 258 b := new(byte) 259 nameMap[b] = &nameData{ 260 name: n, 261 tag: tag, 262 exported: exported, 263 } 264 return name{ 265 bytes: b, 266 } 267 } 268 269 var nameOffList []name 270 271 func (t *rtype) nameOff(off nameOff) name { 272 return nameOffList[int(off)] 273 } 274 275 func newNameOff(n name) nameOff { 276 i := len(nameOffList) 277 nameOffList = append(nameOffList, n) 278 return nameOff(i) 279 } 280 281 var typeOffList []*rtype 282 283 func (t *rtype) typeOff(off typeOff) *rtype { 284 return typeOffList[int(off)] 285 } 286 287 func newTypeOff(t *rtype) typeOff { 288 i := len(typeOffList) 289 typeOffList = append(typeOffList, t) 290 return typeOff(i) 291 } 292 293 // addReflectOff adds a pointer to the reflection lookup map in the runtime. 294 // It returns a new ID that can be used as a typeOff or textOff, and will 295 // be resolved correctly. Implemented in the runtime package. 296 func addReflectOff(ptr unsafe.Pointer) int32 { 297 i := len(typeOffList) 298 typeOffList = append(typeOffList, (*rtype)(ptr)) 299 return int32(i) 300 } 301 302 func internalStr(strObj *js.Object) string { 303 var c struct{ str string } 304 js.InternalObject(c).Set("str", strObj) // get string without internalizing 305 return c.str 306 } 307 308 func isWrapped(typ Type) bool { 309 return jsType(typ).Get("wrapped").Bool() 310 } 311 312 func copyStruct(dst, src *js.Object, typ Type) { 313 fields := jsType(typ).Get("fields") 314 for i := 0; i < fields.Length(); i++ { 315 prop := fields.Index(i).Get("prop").String() 316 dst.Set(prop, src.Get(prop)) 317 } 318 } 319 320 func makeValue(t Type, v *js.Object, fl flag) Value { 321 rt := t.common() 322 if t.Kind() == Array || t.Kind() == Struct || t.Kind() == Ptr { 323 return Value{rt, unsafe.Pointer(v.Unsafe()), fl | flag(t.Kind())} 324 } 325 return Value{rt, unsafe.Pointer(js.Global.Call("$newDataPointer", v, jsType(rt.ptrTo())).Unsafe()), fl | flag(t.Kind()) | flagIndir} 326 } 327 328 func MakeSlice(typ Type, len, cap int) Value { 329 if typ.Kind() != Slice { 330 panic("reflect.MakeSlice of non-slice type") 331 } 332 if len < 0 { 333 panic("reflect.MakeSlice: negative len") 334 } 335 if cap < 0 { 336 panic("reflect.MakeSlice: negative cap") 337 } 338 if len > cap { 339 panic("reflect.MakeSlice: len > cap") 340 } 341 342 return makeValue(typ, js.Global.Call("$makeSlice", jsType(typ), len, cap, js.InternalObject(func() *js.Object { return jsType(typ.Elem()).Call("zero") })), 0) 343 } 344 345 func TypeOf(i interface{}) Type { 346 if !initialized { // avoid error of uint8Type 347 return &rtype{} 348 } 349 if i == nil { 350 return nil 351 } 352 return reflectType(js.InternalObject(i).Get("constructor")) 353 } 354 355 func ValueOf(i interface{}) Value { 356 if i == nil { 357 return Value{} 358 } 359 return makeValue(reflectType(js.InternalObject(i).Get("constructor")), js.InternalObject(i).Get("$val"), 0) 360 } 361 362 func ArrayOf(count int, elem Type) Type { 363 return reflectType(js.Global.Call("$arrayType", jsType(elem), count)) 364 } 365 366 func ChanOf(dir ChanDir, t Type) Type { 367 return reflectType(js.Global.Call("$chanType", jsType(t), dir == SendDir, dir == RecvDir)) 368 } 369 370 func FuncOf(in, out []Type, variadic bool) Type { 371 if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) { 372 panic("reflect.FuncOf: last arg of variadic func must be slice") 373 } 374 375 jsIn := make([]*js.Object, len(in)) 376 for i, v := range in { 377 jsIn[i] = jsType(v) 378 } 379 jsOut := make([]*js.Object, len(out)) 380 for i, v := range out { 381 jsOut[i] = jsType(v) 382 } 383 return reflectType(js.Global.Call("$funcType", jsIn, jsOut, variadic)) 384 } 385 386 func MapOf(key, elem Type) Type { 387 switch key.Kind() { 388 case Func, Map, Slice: 389 panic("reflect.MapOf: invalid key type " + key.String()) 390 } 391 392 return reflectType(js.Global.Call("$mapType", jsType(key), jsType(elem))) 393 } 394 395 func (t *rtype) ptrTo() *rtype { 396 return reflectType(js.Global.Call("$ptrType", jsType(t))) 397 } 398 399 func SliceOf(t Type) Type { 400 return reflectType(js.Global.Call("$sliceType", jsType(t))) 401 } 402 403 // func StructOf(fields []StructField) Type { 404 // jsFields := make([]*js.Object, len(fields)) 405 // fset := map[string]struct{}{} 406 // for i, f := range fields { 407 // if f.Type == nil { 408 // panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") 409 // } 410 411 // name := f.Name 412 // if name == "" { 413 // // Embedded field 414 // if f.Type.Kind() == Ptr { 415 // // Embedded ** and *interface{} are illegal 416 // elem := f.Type.Elem() 417 // if k := elem.Kind(); k == Ptr || k == Interface { 418 // panic("reflect.StructOf: illegal anonymous field type " + f.Type.String()) 419 // } 420 // name = elem.String() 421 // } else { 422 // name = f.Type.String() 423 // } 424 // } 425 426 // if _, dup := fset[name]; dup { 427 // panic("reflect.StructOf: duplicate field " + name) 428 // } 429 // fset[name] = struct{}{} 430 431 // jsf := js.Global.Get("Object").New() 432 // jsf.Set("prop", name) 433 // jsf.Set("name", name) 434 // jsf.Set("exported", true) 435 // jsf.Set("typ", jsType(f.Type)) 436 // jsf.Set("tag", f.Tag) 437 // jsFields[i] = jsf 438 // } 439 // return reflectType(js.Global.Call("$structType", "", jsFields)) 440 // } 441 442 func Zero(typ Type) Value { 443 return makeValue(typ, jsType(typ).Call("zero"), 0) 444 } 445 446 func unsafe_New(typ *rtype) unsafe.Pointer { 447 switch typ.Kind() { 448 case Struct: 449 return unsafe.Pointer(jsType(typ).Get("ptr").New().Unsafe()) 450 case Array: 451 return unsafe.Pointer(jsType(typ).Call("zero").Unsafe()) 452 default: 453 return unsafe.Pointer(js.Global.Call("$newDataPointer", jsType(typ).Call("zero"), jsType(typ.ptrTo())).Unsafe()) 454 } 455 } 456 457 func makeInt(f flag, bits uint64, t Type) Value { 458 typ := t.common() 459 ptr := unsafe_New(typ) 460 switch typ.Kind() { 461 case Int8: 462 *(*int8)(ptr) = int8(bits) 463 case Int16: 464 *(*int16)(ptr) = int16(bits) 465 case Int, Int32: 466 *(*int32)(ptr) = int32(bits) 467 case Int64: 468 *(*int64)(ptr) = int64(bits) 469 case Uint8: 470 *(*uint8)(ptr) = uint8(bits) 471 case Uint16: 472 *(*uint16)(ptr) = uint16(bits) 473 case Uint, Uint32, Uintptr: 474 *(*uint32)(ptr) = uint32(bits) 475 case Uint64: 476 *(*uint64)(ptr) = uint64(bits) 477 } 478 return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} 479 } 480 481 func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { 482 if typ.Kind() != Func { 483 panic("reflect: call of MakeFunc with non-Func type") 484 } 485 486 t := typ.common() 487 ftyp := (*funcType)(unsafe.Pointer(t)) 488 489 fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { 490 args := make([]Value, ftyp.NumIn()) 491 for i := range args { 492 argType := ftyp.In(i).common() 493 args[i] = makeValue(argType, arguments[i], 0) 494 } 495 resultsSlice := fn(args) 496 switch ftyp.NumOut() { 497 case 0: 498 return nil 499 case 1: 500 return resultsSlice[0].object() 501 default: 502 results := js.Global.Get("Array").New(ftyp.NumOut()) 503 for i, r := range resultsSlice { 504 results.SetIndex(i, r.object()) 505 } 506 return results 507 } 508 }) 509 510 return Value{t, unsafe.Pointer(fv.Unsafe()), flag(Func)} 511 } 512 513 func typedmemmove(t *rtype, dst, src unsafe.Pointer) { 514 js.InternalObject(dst).Call("$set", js.InternalObject(src).Call("$get")) 515 } 516 517 func loadScalar(p unsafe.Pointer, n uintptr) uintptr { 518 return js.InternalObject(p).Call("$get").Unsafe() 519 } 520 521 func makechan(typ *rtype, size int) (ch unsafe.Pointer) { 522 ctyp := (*chanType)(unsafe.Pointer(typ)) 523 return unsafe.Pointer(js.Global.Get("$Chan").New(jsType(ctyp.elem), size).Unsafe()) 524 } 525 526 func makemap(t *rtype, cap int) (m unsafe.Pointer) { 527 return unsafe.Pointer(js.Global.Get("Object").New().Unsafe()) 528 } 529 530 func keyFor(t *rtype, key unsafe.Pointer) (*js.Object, string) { 531 kv := js.InternalObject(key) 532 if kv.Get("$get") != js.Undefined { 533 kv = kv.Call("$get") 534 } 535 k := jsType(t.Key()).Call("keyFor", kv).String() 536 return kv, k 537 } 538 539 func mapaccess(t *rtype, m, key unsafe.Pointer) unsafe.Pointer { 540 _, k := keyFor(t, key) 541 entry := js.InternalObject(m).Get(k) 542 if entry == js.Undefined { 543 return nil 544 } 545 return unsafe.Pointer(js.Global.Call("$newDataPointer", entry.Get("v"), jsType(PtrTo(t.Elem()))).Unsafe()) 546 } 547 548 func mapassign(t *rtype, m, key, val unsafe.Pointer) { 549 kv, k := keyFor(t, key) 550 jsVal := js.InternalObject(val).Call("$get") 551 et := t.Elem() 552 if et.Kind() == Struct { 553 newVal := jsType(et).Call("zero") 554 copyStruct(newVal, jsVal, et) 555 jsVal = newVal 556 } 557 entry := js.Global.Get("Object").New() 558 entry.Set("k", kv) 559 entry.Set("v", jsVal) 560 js.InternalObject(m).Set(k, entry) 561 } 562 563 func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer) { 564 _, k := keyFor(t, key) 565 js.InternalObject(m).Delete(k) 566 } 567 568 type mapIter struct { 569 t Type 570 m *js.Object 571 keys *js.Object 572 i int 573 574 // last is the last object the iterator indicates. If this object exists, the functions that return the 575 // current key or value returns this object, regardless of the current iterator. It is because the current 576 // iterator might be stale due to key deletion in a loop. 577 last *js.Object 578 } 579 580 func (iter *mapIter) skipUntilValidKey() { 581 for iter.i < iter.keys.Length() { 582 k := iter.keys.Index(iter.i) 583 if iter.m.Get(k.String()) != js.Undefined { 584 break 585 } 586 // The key is already deleted. Move on the next item. 587 iter.i++ 588 } 589 } 590 591 func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer { 592 return unsafe.Pointer(&mapIter{t, js.InternalObject(m), js.Global.Call("$keys", js.InternalObject(m)), 0, nil}) 593 } 594 595 type TypeEx interface { 596 Type 597 Key() Type 598 } 599 600 func mapiterkey(it unsafe.Pointer) unsafe.Pointer { 601 iter := (*mapIter)(it) 602 var kv *js.Object 603 if iter.last != nil { 604 kv = iter.last 605 } else { 606 iter.skipUntilValidKey() 607 if iter.i == iter.keys.Length() { 608 return nil 609 } 610 k := iter.keys.Index(iter.i) 611 kv = iter.m.Get(k.String()) 612 613 // Record the key-value pair for later accesses. 614 iter.last = kv 615 } 616 return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("k"), jsType(PtrTo(iter.t.(TypeEx).Key()))).Unsafe()) 617 } 618 619 // Go 1.12 620 func mapitervalue(it unsafe.Pointer) unsafe.Pointer { 621 iter := (*mapIter)(it) 622 var kv *js.Object 623 if iter.last != nil { 624 kv = iter.last 625 } else { 626 iter.skipUntilValidKey() 627 if iter.i == iter.keys.Length() { 628 return nil 629 } 630 k := iter.keys.Index(iter.i) 631 kv = iter.m.Get(k.String()) 632 iter.last = kv 633 } 634 return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("v"), jsType(PtrTo(iter.t.Elem()))).Unsafe()) 635 } 636 637 // Go 1.13 638 func mapiterelem(it unsafe.Pointer) unsafe.Pointer { 639 iter := (*mapIter)(it) 640 var kv *js.Object 641 if iter.last != nil { 642 kv = iter.last 643 } else { 644 iter.skipUntilValidKey() 645 if iter.i == iter.keys.Length() { 646 return nil 647 } 648 k := iter.keys.Index(iter.i) 649 kv = iter.m.Get(k.String()) 650 iter.last = kv 651 } 652 return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("v"), jsType(PtrTo(iter.t.Elem()))).Unsafe()) 653 } 654 655 func mapiternext(it unsafe.Pointer) { 656 iter := (*mapIter)(it) 657 iter.last = nil 658 iter.i++ 659 } 660 661 func maplen(m unsafe.Pointer) int { 662 return js.Global.Call("$keys", js.InternalObject(m)).Length() 663 } 664 665 func cvtDirect(v Value, typ Type) Value { 666 var srcVal = v.object() 667 if srcVal == jsType(v.typ).Get("nil") { 668 return makeValue(typ, jsType(typ).Get("nil"), v.flag) 669 } 670 671 var val *js.Object 672 switch k := typ.Kind(); k { 673 case Slice: 674 slice := jsType(typ).New(srcVal.Get("$array")) 675 slice.Set("$offset", srcVal.Get("$offset")) 676 slice.Set("$length", srcVal.Get("$length")) 677 slice.Set("$capacity", srcVal.Get("$capacity")) 678 val = js.Global.Call("$newDataPointer", slice, jsType(PtrTo(typ))) 679 case Ptr: 680 if typ.Elem().Kind() == Struct { 681 if typ.Elem() == v.typ.Elem() { 682 val = srcVal 683 break 684 } 685 val = jsType(typ).New() 686 copyStruct(val, srcVal, typ.Elem()) 687 break 688 } 689 val = jsType(typ).New(srcVal.Get("$get"), srcVal.Get("$set")) 690 case Struct: 691 val = jsType(typ).Get("ptr").New() 692 copyStruct(val, srcVal, typ) 693 case Array, Bool, Chan, Func, Interface, Map, String: 694 val = js.InternalObject(v.ptr) 695 default: 696 panic(&ValueError{"reflect.Convert", k}) 697 } 698 return Value{typ.common(), unsafe.Pointer(val.Unsafe()), v.flag.ro() | v.flag&flagIndir | flag(typ.Kind())} 699 } 700 701 func Copy(dst, src Value) int { 702 dk := dst.kind() 703 if dk != Array && dk != Slice { 704 panic(&ValueError{"reflect.Copy", dk}) 705 } 706 if dk == Array { 707 dst.mustBeAssignable() 708 } 709 dst.mustBeExported() 710 711 sk := src.kind() 712 var stringCopy bool 713 if sk != Array && sk != Slice { 714 stringCopy = sk == String && dst.typ.Elem().Kind() == Uint8 715 if !stringCopy { 716 panic(&ValueError{"reflect.Copy", sk}) 717 } 718 } 719 src.mustBeExported() 720 721 if !stringCopy { 722 typesMustMatch("reflect.Copy", dst.typ.Elem(), src.typ.Elem()) 723 } 724 725 dstVal := dst.object() 726 if dk == Array { 727 dstVal = jsType(SliceOf(dst.typ.Elem())).New(dstVal) 728 } 729 730 srcVal := src.object() 731 if sk == Array { 732 srcVal = jsType(SliceOf(src.typ.Elem())).New(srcVal) 733 } 734 735 if stringCopy { 736 return js.Global.Call("$copyString", dstVal, srcVal).Int() 737 } 738 return js.Global.Call("$copySlice", dstVal, srcVal).Int() 739 } 740 741 func methodReceiver(op string, v Value, i int) (_ *rtype, t *funcType, fn unsafe.Pointer) { 742 var prop string 743 if v.typ.Kind() == Interface { 744 tt := (*interfaceType)(unsafe.Pointer(v.typ)) 745 if i < 0 || i >= len(tt.methods) { 746 panic("reflect: internal error: invalid method index") 747 } 748 m := &tt.methods[i] 749 if !tt.nameOff(m.name).isExported() { 750 panic("reflect: " + op + " of unexported method") 751 } 752 t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ))) 753 prop = tt.nameOff(m.name).name() 754 } else { 755 ms := v.typ.exportedMethods() 756 if uint(i) >= uint(len(ms)) { 757 panic("reflect: internal error: invalid method index") 758 } 759 m := ms[i] 760 if !v.typ.nameOff(m.name).isExported() { 761 panic("reflect: " + op + " of unexported method") 762 } 763 t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp))) 764 prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String() 765 } 766 rcvr := v.object() 767 if isWrapped(v.typ) { 768 rcvr = jsType(v.typ).New(rcvr) 769 } 770 fn = unsafe.Pointer(rcvr.Get(prop).Unsafe()) 771 return 772 } 773 774 func valueInterface(v Value) interface{} { 775 if v.flag == 0 { 776 panic(&ValueError{"reflect.Value.Interface", 0}) 777 } 778 779 if v.flag&flagMethod != 0 { 780 v = makeMethodValue("Interface", v) 781 } 782 783 if isWrapped(v.typ) { 784 return interface{}(unsafe.Pointer(jsType(v.typ).New(v.object()).Unsafe())) 785 } 786 return interface{}(unsafe.Pointer(v.object().Unsafe())) 787 } 788 789 func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) { 790 js.InternalObject(dst).Call("$set", js.InternalObject(src)) 791 } 792 793 func methodName() string { 794 return "?FIXME?" 795 } 796 797 func makeMethodValue(op string, v Value) Value { 798 if v.flag&flagMethod == 0 { 799 panic("reflect: internal error: invalid use of makePartialFunc") 800 } 801 802 _, _, fn := methodReceiver(op, v, int(v.flag)>>flagMethodShift) 803 rcvr := v.object() 804 if isWrapped(v.typ) { 805 rcvr = jsType(v.typ).New(rcvr) 806 } 807 fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { 808 return js.InternalObject(fn).Call("apply", rcvr, arguments) 809 }) 810 return Value{v.Type().common(), unsafe.Pointer(fv.Unsafe()), v.flag.ro() | flag(Func)} 811 } 812 813 var jsObjectPtr = reflectType(js.Global.Get("$jsObjectPtr")) 814 815 func wrapJsObject(typ Type, val *js.Object) *js.Object { 816 if typ == jsObjectPtr { 817 return jsType(jsObjectPtr).New(val) 818 } 819 return val 820 } 821 822 func unwrapJsObject(typ Type, val *js.Object) *js.Object { 823 if typ == jsObjectPtr { 824 return val.Get("object") 825 } 826 return val 827 } 828 829 func getJsTag(tag string) string { 830 for tag != "" { 831 // skip leading space 832 i := 0 833 for i < len(tag) && tag[i] == ' ' { 834 i++ 835 } 836 tag = tag[i:] 837 if tag == "" { 838 break 839 } 840 841 // scan to colon. 842 // a space or a quote is a syntax error 843 i = 0 844 for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' { 845 i++ 846 } 847 if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { 848 break 849 } 850 name := string(tag[:i]) 851 tag = tag[i+1:] 852 853 // scan quoted string to find value 854 i = 1 855 for i < len(tag) && tag[i] != '"' { 856 if tag[i] == '\\' { 857 i++ 858 } 859 i++ 860 } 861 if i >= len(tag) { 862 break 863 } 864 qvalue := string(tag[:i+1]) 865 tag = tag[i+1:] 866 867 if name == "js" { 868 value, _ := unquote(qvalue) 869 return value 870 } 871 } 872 return "" 873 } 874 875 // PtrTo returns the pointer type with element t. 876 // For example, if t represents type Foo, PtrTo(t) represents *Foo. 877 func PtrTo(t Type) Type { 878 return t.(*rtype).ptrTo() 879 } 880 881 // copyVal returns a Value containing the map key or value at ptr, 882 // allocating a new variable as needed. 883 func copyVal(typ *rtype, fl flag, ptr unsafe.Pointer) Value { 884 if ifaceIndir(typ) { 885 // Copy result so future changes to the map 886 // won't change the underlying value. 887 c := unsafe_New(typ) 888 typedmemmove(typ, c, ptr) 889 return Value{typ, c, fl | flagIndir} 890 } 891 return Value{typ, *(*unsafe.Pointer)(ptr), fl} 892 } 893 894 var selectHelper = js.Global.Get("$select").Interface().(func(...interface{}) *js.Object) 895 896 func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool) { 897 comms := [][]*js.Object{{js.InternalObject(ch)}} 898 if nb { 899 comms = append(comms, []*js.Object{}) 900 } 901 selectRes := selectHelper(comms) 902 if nb && selectRes.Index(0).Int() == 1 { 903 return false, false 904 } 905 recvRes := selectRes.Index(1) 906 js.InternalObject(val).Call("$set", recvRes.Index(0)) 907 return true, recvRes.Index(1).Bool() 908 } 909 910 func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool { 911 comms := [][]*js.Object{{js.InternalObject(ch), js.InternalObject(val).Call("$get")}} 912 if nb { 913 comms = append(comms, []*js.Object{}) 914 } 915 selectRes := selectHelper(comms) 916 if nb && selectRes.Index(0).Int() == 1 { 917 return false 918 } 919 return true 920 } 921 922 func rselect(rselects []runtimeSelect) (chosen int, recvOK bool) { 923 comms := make([][]*js.Object, len(rselects)) 924 for i, s := range rselects { 925 switch SelectDir(s.dir) { 926 case SelectDefault: 927 comms[i] = []*js.Object{} 928 case SelectRecv: 929 ch := js.Global.Get("$chanNil") 930 if js.InternalObject(s.ch) != js.InternalObject(0) { 931 ch = js.InternalObject(s.ch) 932 } 933 comms[i] = []*js.Object{ch} 934 case SelectSend: 935 ch := js.Global.Get("$chanNil") 936 var val *js.Object 937 if js.InternalObject(s.ch) != js.InternalObject(0) { 938 ch = js.InternalObject(s.ch) 939 val = js.InternalObject(s.val).Call("$get") 940 } 941 comms[i] = []*js.Object{ch, val} 942 } 943 } 944 selectRes := selectHelper(comms) 945 c := selectRes.Index(0).Int() 946 if SelectDir(rselects[c].dir) == SelectRecv { 947 recvRes := selectRes.Index(1) 948 js.InternalObject(rselects[c].val).Call("$set", recvRes.Index(0)) 949 return c, recvRes.Index(1).Bool() 950 } 951 return c, false 952 } 953 954 func DeepEqual(a1, a2 interface{}) bool { 955 i1 := js.InternalObject(a1) 956 i2 := js.InternalObject(a2) 957 if i1 == i2 { 958 return true 959 } 960 if i1 == nil || i2 == nil || i1.Get("constructor") != i2.Get("constructor") { 961 return false 962 } 963 return deepValueEqualJs(ValueOf(a1), ValueOf(a2), nil) 964 } 965 966 func deepValueEqualJs(v1, v2 Value, visited [][2]unsafe.Pointer) bool { 967 if !v1.IsValid() || !v2.IsValid() { 968 return !v1.IsValid() && !v2.IsValid() 969 } 970 if v1.Type() != v2.Type() { 971 return false 972 } 973 if v1.Type() == jsObjectPtr { 974 return unwrapJsObject(jsObjectPtr, v1.object()) == unwrapJsObject(jsObjectPtr, v2.object()) 975 } 976 977 switch v1.Kind() { 978 case Array, Map, Slice, Struct: 979 for _, entry := range visited { 980 if v1.ptr == entry[0] && v2.ptr == entry[1] { 981 return true 982 } 983 } 984 visited = append(visited, [2]unsafe.Pointer{v1.ptr, v2.ptr}) 985 } 986 987 switch v1.Kind() { 988 case Array, Slice: 989 if v1.Kind() == Slice { 990 if v1.IsNil() != v2.IsNil() { 991 return false 992 } 993 if v1.object() == v2.object() { 994 return true 995 } 996 } 997 var n = v1.Len() 998 if n != v2.Len() { 999 return false 1000 } 1001 for i := 0; i < n; i++ { 1002 if !deepValueEqualJs(v1.Index(i), v2.Index(i), visited) { 1003 return false 1004 } 1005 } 1006 return true 1007 case Interface: 1008 if v1.IsNil() || v2.IsNil() { 1009 return v1.IsNil() && v2.IsNil() 1010 } 1011 return deepValueEqualJs(v1.Elem(), v2.Elem(), visited) 1012 case Ptr: 1013 return deepValueEqualJs(v1.Elem(), v2.Elem(), visited) 1014 case Struct: 1015 var n = v1.NumField() 1016 for i := 0; i < n; i++ { 1017 if !deepValueEqualJs(v1.Field(i), v2.Field(i), visited) { 1018 return false 1019 } 1020 } 1021 return true 1022 case Map: 1023 if v1.IsNil() != v2.IsNil() { 1024 return false 1025 } 1026 if v1.object() == v2.object() { 1027 return true 1028 } 1029 var keys = v1.MapKeys() 1030 if len(keys) != v2.Len() { 1031 return false 1032 } 1033 for _, k := range keys { 1034 val1 := v1.MapIndex(k) 1035 val2 := v2.MapIndex(k) 1036 if !val1.IsValid() || !val2.IsValid() || !deepValueEqualJs(val1, val2, visited) { 1037 return false 1038 } 1039 } 1040 return true 1041 case Func: 1042 return v1.IsNil() && v2.IsNil() 1043 case UnsafePointer: 1044 return v1.object() == v2.object() 1045 } 1046 1047 return js.Global.Call("$interfaceIsEqual", js.InternalObject(valueInterface(v1)), js.InternalObject(valueInterface(v2))).Bool() 1048 }