github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/natives/src/reflect/reflect.go (about)

     1  // +build js
     2  
     3  package reflect
     4  
     5  import (
     6  	"errors"
     7  	"strconv"
     8  	"unsafe"
     9  
    10  	"github.com/gopherjs/gopherjs/js"
    11  )
    12  
    13  var initialized = false
    14  
    15  func init() {
    16  	// avoid dead code elimination
    17  	used := func(i interface{}) {}
    18  	used(rtype{})
    19  	used(uncommonType{})
    20  	used(method{})
    21  	used(arrayType{})
    22  	used(chanType{})
    23  	used(funcType{})
    24  	used(interfaceType{})
    25  	used(mapType{})
    26  	used(ptrType{})
    27  	used(sliceType{})
    28  	used(structType{})
    29  	used(imethod{})
    30  	used(structField{})
    31  
    32  	initialized = true
    33  	uint8Type = TypeOf(uint8(0)).(*rtype) // set for real
    34  }
    35  
    36  func jsType(typ Type) *js.Object {
    37  	return js.InternalObject(typ).Get("jsType")
    38  }
    39  
    40  func reflectType(typ *js.Object) *rtype {
    41  	return _reflectType(typ, internalStr)
    42  }
    43  
    44  func _reflectType(typ *js.Object, fnObjStr func(strObj *js.Object) string) *rtype {
    45  	if typ.Get("reflectType") == js.Undefined {
    46  		rt := &rtype{
    47  			size: uintptr(typ.Get("size").Int()),
    48  			kind: uint8(typ.Get("kind").Int()),
    49  			str:  newNameOff(newName(fnObjStr(typ.Get("string")), "", typ.Get("exported").Bool())),
    50  		}
    51  		js.InternalObject(rt).Set("jsType", typ)
    52  		typ.Set("reflectType", js.InternalObject(rt))
    53  
    54  		methodSet := js.Global.Call("$methodSet", typ)
    55  		if methodSet.Length() != 0 || typ.Get("named").Bool() {
    56  			rt.tflag |= tflagUncommon
    57  			if typ.Get("named").Bool() {
    58  				rt.tflag |= tflagNamed
    59  			}
    60  			var reflectMethods []method
    61  			for i := 0; i < methodSet.Length(); i++ { // Exported methods first.
    62  				m := methodSet.Index(i)
    63  				exported := fnObjStr(m.Get("pkg")) == ""
    64  				if !exported {
    65  					continue
    66  				}
    67  				reflectMethods = append(reflectMethods, method{
    68  					name: newNameOff(newName(fnObjStr(m.Get("name")), "", exported)),
    69  					mtyp: newTypeOff(reflectType(m.Get("typ"))),
    70  				})
    71  			}
    72  			xcount := uint16(len(reflectMethods))
    73  			for i := 0; i < methodSet.Length(); i++ { // Unexported methods second.
    74  				m := methodSet.Index(i)
    75  				exported := fnObjStr(m.Get("pkg")) == ""
    76  				if exported {
    77  					continue
    78  				}
    79  				reflectMethods = append(reflectMethods, method{
    80  					name: newNameOff(newName(fnObjStr(m.Get("name")), "", exported)),
    81  					mtyp: newTypeOff(reflectType(m.Get("typ"))),
    82  				})
    83  			}
    84  			ut := &uncommonType{
    85  				pkgPath:  newNameOff(newName(fnObjStr(typ.Get("pkg")), "", false)),
    86  				mcount:   uint16(methodSet.Length()),
    87  				xcount:   xcount,
    88  				_methods: reflectMethods,
    89  			}
    90  			js.InternalObject(ut).Set("jsType", typ)
    91  			js.InternalObject(rt).Set("uncommonType", js.InternalObject(ut))
    92  		}
    93  
    94  		switch rt.Kind() {
    95  		case Array:
    96  			setKindType(rt, &arrayType{
    97  				elem: reflectType(typ.Get("elem")),
    98  				len:  uintptr(typ.Get("len").Int()),
    99  			})
   100  		case Chan:
   101  			dir := BothDir
   102  			if typ.Get("sendOnly").Bool() {
   103  				dir = SendDir
   104  			}
   105  			if typ.Get("recvOnly").Bool() {
   106  				dir = RecvDir
   107  			}
   108  			setKindType(rt, &chanType{
   109  				elem: reflectType(typ.Get("elem")),
   110  				dir:  uintptr(dir),
   111  			})
   112  		case Func:
   113  			params := typ.Get("params")
   114  			in := make([]*rtype, params.Length())
   115  			for i := range in {
   116  				in[i] = reflectType(params.Index(i))
   117  			}
   118  			results := typ.Get("results")
   119  			out := make([]*rtype, results.Length())
   120  			for i := range out {
   121  				out[i] = reflectType(results.Index(i))
   122  			}
   123  			outCount := uint16(results.Length())
   124  			if typ.Get("variadic").Bool() {
   125  				outCount |= 1 << 15
   126  			}
   127  			setKindType(rt, &funcType{
   128  				rtype:    *rt,
   129  				inCount:  uint16(params.Length()),
   130  				outCount: outCount,
   131  				_in:      in,
   132  				_out:     out,
   133  			})
   134  		case Interface:
   135  			methods := typ.Get("methods")
   136  			imethods := make([]imethod, methods.Length())
   137  			for i := range imethods {
   138  				m := methods.Index(i)
   139  				imethods[i] = imethod{
   140  					name: newNameOff(newName(fnObjStr(m.Get("name")), "", fnObjStr(m.Get("pkg")) == "")),
   141  					typ:  newTypeOff(reflectType(m.Get("typ"))),
   142  				}
   143  			}
   144  			setKindType(rt, &interfaceType{
   145  				rtype:   *rt,
   146  				pkgPath: newName(fnObjStr(typ.Get("pkg")), "", false),
   147  				methods: imethods,
   148  			})
   149  		case Map:
   150  			setKindType(rt, &mapType{
   151  				key:  reflectType(typ.Get("key")),
   152  				elem: reflectType(typ.Get("elem")),
   153  			})
   154  		case Ptr:
   155  			setKindType(rt, &ptrType{
   156  				elem: reflectType(typ.Get("elem")),
   157  			})
   158  		case Slice:
   159  			setKindType(rt, &sliceType{
   160  				elem: reflectType(typ.Get("elem")),
   161  			})
   162  		case Struct:
   163  			fields := typ.Get("fields")
   164  			reflectFields := make([]structField, fields.Length())
   165  			for i := range reflectFields {
   166  				f := fields.Index(i)
   167  				offsetEmbed := uintptr(i) << 1
   168  				if f.Get("embedded").Bool() {
   169  					offsetEmbed |= 1
   170  				}
   171  				reflectFields[i] = structField{
   172  					name:        newName(fnObjStr(f.Get("name")), fnObjStr(f.Get("tag")), f.Get("exported").Bool()),
   173  					typ:         reflectType(f.Get("typ")),
   174  					offsetEmbed: offsetEmbed,
   175  				}
   176  			}
   177  			setKindType(rt, &structType{
   178  				rtype:   *rt,
   179  				pkgPath: newName(fnObjStr(typ.Get("pkgPath")), "", false),
   180  				fields:  reflectFields,
   181  			})
   182  		}
   183  	}
   184  
   185  	return (*rtype)(unsafe.Pointer(typ.Get("reflectType").Unsafe()))
   186  }
   187  
   188  func setKindType(rt *rtype, kindType interface{}) {
   189  	js.InternalObject(rt).Set("kindType", js.InternalObject(kindType))
   190  	js.InternalObject(kindType).Set("rtype", js.InternalObject(rt))
   191  }
   192  
   193  type uncommonType struct {
   194  	pkgPath nameOff
   195  	mcount  uint16
   196  	xcount  uint16
   197  	moff    uint32
   198  
   199  	_methods []method
   200  }
   201  
   202  func (t *uncommonType) methods() []method {
   203  	return t._methods
   204  }
   205  
   206  func (t *uncommonType) exportedMethods() []method {
   207  	return t._methods[:t.xcount:t.xcount]
   208  }
   209  
   210  func (t *rtype) uncommon() *uncommonType {
   211  	obj := js.InternalObject(t).Get("uncommonType")
   212  	if obj == js.Undefined {
   213  		return nil
   214  	}
   215  	return (*uncommonType)(unsafe.Pointer(obj.Unsafe()))
   216  }
   217  
   218  type funcType struct {
   219  	rtype    `reflect:"func"`
   220  	inCount  uint16
   221  	outCount uint16
   222  
   223  	_in  []*rtype
   224  	_out []*rtype
   225  }
   226  
   227  func (t *funcType) in() []*rtype {
   228  	return t._in
   229  }
   230  
   231  func (t *funcType) out() []*rtype {
   232  	return t._out
   233  }
   234  
   235  type name struct {
   236  	bytes *byte
   237  }
   238  
   239  type nameData struct {
   240  	name     string
   241  	tag      string
   242  	exported bool
   243  }
   244  
   245  var nameMap = make(map[*byte]*nameData)
   246  
   247  func (n name) name() (s string) { return nameMap[n.bytes].name }
   248  func (n name) tag() (s string)  { return nameMap[n.bytes].tag }
   249  func (n name) pkgPath() string  { return "" }
   250  func (n name) isExported() bool { return nameMap[n.bytes].exported }
   251  
   252  func newName(n, tag string, exported bool) name {
   253  	b := new(byte)
   254  	nameMap[b] = &nameData{
   255  		name:     n,
   256  		tag:      tag,
   257  		exported: exported,
   258  	}
   259  	return name{
   260  		bytes: b,
   261  	}
   262  }
   263  
   264  var nameOffList []name
   265  
   266  func (t *rtype) nameOff(off nameOff) name {
   267  	return nameOffList[int(off)]
   268  }
   269  
   270  func newNameOff(n name) nameOff {
   271  	i := len(nameOffList)
   272  	nameOffList = append(nameOffList, n)
   273  	return nameOff(i)
   274  }
   275  
   276  func resolveReflectName(n name) nameOff {
   277  	return newNameOff(n)
   278  }
   279  
   280  var typeOffList []*rtype
   281  
   282  func (t *rtype) typeOff(off typeOff) *rtype {
   283  	return typeOffList[int(off)]
   284  }
   285  
   286  func newTypeOff(t *rtype) typeOff {
   287  	i := len(typeOffList)
   288  	typeOffList = append(typeOffList, t)
   289  	return typeOff(i)
   290  }
   291  
   292  // addReflectOff adds a pointer to the reflection lookup map in the runtime.
   293  // It returns a new ID that can be used as a typeOff or textOff, and will
   294  // be resolved correctly. Implemented in the runtime package.
   295  func addReflectOff(ptr unsafe.Pointer) int32 {
   296  	i := len(typeOffList)
   297  	typeOffList = append(typeOffList, (*rtype)(ptr))
   298  	return int32(i)
   299  }
   300  
   301  func internalStr(strObj *js.Object) string {
   302  	var c struct{ str string }
   303  	js.InternalObject(c).Set("str", strObj) // get string without internalizing
   304  	return c.str
   305  }
   306  
   307  func isWrapped(typ Type) bool {
   308  	return jsType(typ).Get("wrapped").Bool()
   309  }
   310  
   311  func copyStruct(dst, src *js.Object, typ Type) {
   312  	fields := jsType(typ).Get("fields")
   313  	for i := 0; i < fields.Length(); i++ {
   314  		prop := fields.Index(i).Get("prop").String()
   315  		dst.Set(prop, src.Get(prop))
   316  	}
   317  }
   318  
   319  func makeValue(t Type, v *js.Object, fl flag) Value {
   320  	rt := t.common()
   321  	if t.Kind() == Array || t.Kind() == Struct || t.Kind() == Ptr {
   322  		return Value{rt, unsafe.Pointer(v.Unsafe()), fl | flag(t.Kind())}
   323  	}
   324  	return Value{rt, unsafe.Pointer(js.Global.Call("$newDataPointer", v, jsType(rt.ptrTo())).Unsafe()), fl | flag(t.Kind()) | flagIndir}
   325  }
   326  
   327  func MakeSlice(typ Type, len, cap int) Value {
   328  	if typ.Kind() != Slice {
   329  		panic("reflect.MakeSlice of non-slice type")
   330  	}
   331  	if len < 0 {
   332  		panic("reflect.MakeSlice: negative len")
   333  	}
   334  	if cap < 0 {
   335  		panic("reflect.MakeSlice: negative cap")
   336  	}
   337  	if len > cap {
   338  		panic("reflect.MakeSlice: len > cap")
   339  	}
   340  
   341  	return makeValue(typ, js.Global.Call("$makeSlice", jsType(typ), len, cap, js.InternalObject(func() *js.Object { return jsType(typ.Elem()).Call("zero") })), 0)
   342  }
   343  
   344  func TypeOf(i interface{}) Type {
   345  	if !initialized { // avoid error of uint8Type
   346  		return &rtype{}
   347  	}
   348  	if i == nil {
   349  		return nil
   350  	}
   351  	return reflectType(js.InternalObject(i).Get("constructor"))
   352  }
   353  
   354  func ValueOf(i interface{}) Value {
   355  	if i == nil {
   356  		return Value{}
   357  	}
   358  	return makeValue(reflectType(js.InternalObject(i).Get("constructor")), js.InternalObject(i).Get("$val"), 0)
   359  }
   360  
   361  func ArrayOf(count int, elem Type) Type {
   362  	return reflectType(js.Global.Call("$arrayType", jsType(elem), count))
   363  }
   364  
   365  func ChanOf(dir ChanDir, t Type) Type {
   366  	return reflectType(js.Global.Call("$chanType", jsType(t), dir == SendDir, dir == RecvDir))
   367  }
   368  
   369  func FuncOf(in, out []Type, variadic bool) Type {
   370  	if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
   371  		panic("reflect.FuncOf: last arg of variadic func must be slice")
   372  	}
   373  
   374  	jsIn := make([]*js.Object, len(in))
   375  	for i, v := range in {
   376  		jsIn[i] = jsType(v)
   377  	}
   378  	jsOut := make([]*js.Object, len(out))
   379  	for i, v := range out {
   380  		jsOut[i] = jsType(v)
   381  	}
   382  	return reflectType(js.Global.Call("$funcType", jsIn, jsOut, variadic))
   383  }
   384  
   385  func MapOf(key, elem Type) Type {
   386  	switch key.Kind() {
   387  	case Func, Map, Slice:
   388  		panic("reflect.MapOf: invalid key type " + key.String())
   389  	}
   390  
   391  	return reflectType(js.Global.Call("$mapType", jsType(key), jsType(elem)))
   392  }
   393  
   394  func (t *rtype) ptrTo() *rtype {
   395  	return reflectType(js.Global.Call("$ptrType", jsType(t)))
   396  }
   397  
   398  func SliceOf(t Type) Type {
   399  	return reflectType(js.Global.Call("$sliceType", jsType(t)))
   400  }
   401  
   402  // func StructOf(fields []StructField) Type {
   403  // 	jsFields := make([]*js.Object, len(fields))
   404  // 	fset := map[string]struct{}{}
   405  // 	for i, f := range fields {
   406  // 		if f.Type == nil {
   407  // 			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
   408  // 		}
   409  
   410  // 		name := f.Name
   411  // 		if name == "" {
   412  // 			// Embedded field
   413  // 			if f.Type.Kind() == Ptr {
   414  // 				// Embedded ** and *interface{} are illegal
   415  // 				elem := f.Type.Elem()
   416  // 				if k := elem.Kind(); k == Ptr || k == Interface {
   417  // 					panic("reflect.StructOf: illegal anonymous field type " + f.Type.String())
   418  // 				}
   419  // 				name = elem.String()
   420  // 			} else {
   421  // 				name = f.Type.String()
   422  // 			}
   423  // 		}
   424  
   425  // 		if _, dup := fset[name]; dup {
   426  // 			panic("reflect.StructOf: duplicate field " + name)
   427  // 		}
   428  // 		fset[name] = struct{}{}
   429  
   430  // 		jsf := js.Global.Get("Object").New()
   431  // 		jsf.Set("prop", name)
   432  // 		jsf.Set("name", name)
   433  // 		jsf.Set("exported", true)
   434  // 		jsf.Set("typ", jsType(f.Type))
   435  // 		jsf.Set("tag", f.Tag)
   436  // 		jsFields[i] = jsf
   437  // 	}
   438  // 	return reflectType(js.Global.Call("$structType", "", jsFields))
   439  // }
   440  
   441  func Zero(typ Type) Value {
   442  	return makeValue(typ, jsType(typ).Call("zero"), 0)
   443  }
   444  
   445  func unsafe_New(typ *rtype) unsafe.Pointer {
   446  	switch typ.Kind() {
   447  	case Struct:
   448  		return unsafe.Pointer(jsType(typ).Get("ptr").New().Unsafe())
   449  	case Array:
   450  		return unsafe.Pointer(jsType(typ).Call("zero").Unsafe())
   451  	default:
   452  		return unsafe.Pointer(js.Global.Call("$newDataPointer", jsType(typ).Call("zero"), jsType(typ.ptrTo())).Unsafe())
   453  	}
   454  }
   455  
   456  func makeInt(f flag, bits uint64, t Type) Value {
   457  	typ := t.common()
   458  	ptr := unsafe_New(typ)
   459  	switch typ.Kind() {
   460  	case Int8:
   461  		*(*int8)(ptr) = int8(bits)
   462  	case Int16:
   463  		*(*int16)(ptr) = int16(bits)
   464  	case Int, Int32:
   465  		*(*int32)(ptr) = int32(bits)
   466  	case Int64:
   467  		*(*int64)(ptr) = int64(bits)
   468  	case Uint8:
   469  		*(*uint8)(ptr) = uint8(bits)
   470  	case Uint16:
   471  		*(*uint16)(ptr) = uint16(bits)
   472  	case Uint, Uint32, Uintptr:
   473  		*(*uint32)(ptr) = uint32(bits)
   474  	case Uint64:
   475  		*(*uint64)(ptr) = uint64(bits)
   476  	}
   477  	return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
   478  }
   479  
   480  func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
   481  	if typ.Kind() != Func {
   482  		panic("reflect: call of MakeFunc with non-Func type")
   483  	}
   484  
   485  	t := typ.common()
   486  	ftyp := (*funcType)(unsafe.Pointer(t))
   487  
   488  	fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} {
   489  		args := make([]Value, ftyp.NumIn())
   490  		for i := range args {
   491  			argType := ftyp.In(i).common()
   492  			args[i] = makeValue(argType, arguments[i], 0)
   493  		}
   494  		resultsSlice := fn(args)
   495  		switch ftyp.NumOut() {
   496  		case 0:
   497  			return nil
   498  		case 1:
   499  			return resultsSlice[0].object()
   500  		default:
   501  			results := js.Global.Get("Array").New(ftyp.NumOut())
   502  			for i, r := range resultsSlice {
   503  				results.SetIndex(i, r.object())
   504  			}
   505  			return results
   506  		}
   507  	})
   508  
   509  	return Value{t, unsafe.Pointer(fv.Unsafe()), flag(Func)}
   510  }
   511  
   512  func typedmemmove(t *rtype, dst, src unsafe.Pointer) {
   513  	js.InternalObject(dst).Call("$set", js.InternalObject(src).Call("$get"))
   514  }
   515  
   516  func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
   517  	return js.InternalObject(p).Call("$get").Unsafe()
   518  }
   519  
   520  func makechan(typ *rtype, size int) (ch unsafe.Pointer) {
   521  	ctyp := (*chanType)(unsafe.Pointer(typ))
   522  	return unsafe.Pointer(js.Global.Get("$Chan").New(jsType(ctyp.elem), size).Unsafe())
   523  }
   524  
   525  func makemap(t *rtype, cap int) (m unsafe.Pointer) {
   526  	return unsafe.Pointer(js.Global.Get("Object").New().Unsafe())
   527  }
   528  
   529  func keyFor(t *rtype, key unsafe.Pointer) (*js.Object, string) {
   530  	kv := js.InternalObject(key)
   531  	if kv.Get("$get") != js.Undefined {
   532  		kv = kv.Call("$get")
   533  	}
   534  	k := jsType(t.Key()).Call("keyFor", kv).String()
   535  	return kv, k
   536  }
   537  
   538  func mapaccess(t *rtype, m, key unsafe.Pointer) unsafe.Pointer {
   539  	_, k := keyFor(t, key)
   540  	entry := js.InternalObject(m).Get(k)
   541  	if entry == js.Undefined {
   542  		return nil
   543  	}
   544  	return unsafe.Pointer(js.Global.Call("$newDataPointer", entry.Get("v"), jsType(PtrTo(t.Elem()))).Unsafe())
   545  }
   546  
   547  func mapassign(t *rtype, m, key, val unsafe.Pointer) {
   548  	kv, k := keyFor(t, key)
   549  	jsVal := js.InternalObject(val).Call("$get")
   550  	et := t.Elem()
   551  	if et.Kind() == Struct {
   552  		newVal := jsType(et).Call("zero")
   553  		copyStruct(newVal, jsVal, et)
   554  		jsVal = newVal
   555  	}
   556  	entry := js.Global.Get("Object").New()
   557  	entry.Set("k", kv)
   558  	entry.Set("v", jsVal)
   559  	js.InternalObject(m).Set(k, entry)
   560  }
   561  
   562  func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer) {
   563  	_, k := keyFor(t, key)
   564  	js.InternalObject(m).Delete(k)
   565  }
   566  
   567  type mapIter struct {
   568  	t    Type
   569  	m    *js.Object
   570  	keys *js.Object
   571  	i    int
   572  
   573  	// last is the last object the iterator indicates. If this object exists, the functions that return the
   574  	// current key or value returns this object, regardless of the current iterator. It is because the current
   575  	// iterator might be stale due to key deletion in a loop.
   576  	last *js.Object
   577  }
   578  
   579  func (iter *mapIter) skipUntilValidKey() {
   580  	for iter.i < iter.keys.Length() {
   581  		k := iter.keys.Index(iter.i)
   582  		if iter.m.Get(k.String()) != js.Undefined {
   583  			break
   584  		}
   585  		// The key is already deleted. Move on the next item.
   586  		iter.i++
   587  	}
   588  }
   589  
   590  func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer {
   591  	return unsafe.Pointer(&mapIter{t, js.InternalObject(m), js.Global.Call("$keys", js.InternalObject(m)), 0, nil})
   592  }
   593  
   594  func mapiterkey(it unsafe.Pointer) unsafe.Pointer {
   595  	iter := (*mapIter)(it)
   596  	var kv *js.Object
   597  	if iter.last != nil {
   598  		kv = iter.last
   599  	} else {
   600  		iter.skipUntilValidKey()
   601  		if iter.i == iter.keys.Length() {
   602  			return nil
   603  		}
   604  		k := iter.keys.Index(iter.i)
   605  		kv = iter.m.Get(k.String())
   606  
   607  		// Record the key-value pair for later accesses.
   608  		iter.last = kv
   609  	}
   610  	return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("k"), jsType(PtrTo(iter.t.Key()))).Unsafe())
   611  }
   612  
   613  // Go 1.12
   614  func mapitervalue(it unsafe.Pointer) unsafe.Pointer {
   615  	iter := (*mapIter)(it)
   616  	var kv *js.Object
   617  	if iter.last != nil {
   618  		kv = iter.last
   619  	} else {
   620  		iter.skipUntilValidKey()
   621  		if iter.i == iter.keys.Length() {
   622  			return nil
   623  		}
   624  		k := iter.keys.Index(iter.i)
   625  		kv = iter.m.Get(k.String())
   626  		iter.last = kv
   627  	}
   628  	return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("v"), jsType(PtrTo(iter.t.Elem()))).Unsafe())
   629  }
   630  
   631  // Go 1.13
   632  func mapiterelem(it unsafe.Pointer) unsafe.Pointer {
   633  	iter := (*mapIter)(it)
   634  	var kv *js.Object
   635  	if iter.last != nil {
   636  		kv = iter.last
   637  	} else {
   638  		iter.skipUntilValidKey()
   639  		if iter.i == iter.keys.Length() {
   640  			return nil
   641  		}
   642  		k := iter.keys.Index(iter.i)
   643  		kv = iter.m.Get(k.String())
   644  		iter.last = kv
   645  	}
   646  	return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("v"), jsType(PtrTo(iter.t.Elem()))).Unsafe())
   647  }
   648  
   649  func mapiternext(it unsafe.Pointer) {
   650  	iter := (*mapIter)(it)
   651  	iter.last = nil
   652  	iter.i++
   653  }
   654  
   655  func maplen(m unsafe.Pointer) int {
   656  	return js.Global.Call("$keys", js.InternalObject(m)).Length()
   657  }
   658  
   659  func cvtDirect(v Value, typ Type) Value {
   660  	var srcVal = v.object()
   661  	if srcVal == jsType(v.typ).Get("nil") {
   662  		return makeValue(typ, jsType(typ).Get("nil"), v.flag)
   663  	}
   664  
   665  	var val *js.Object
   666  	switch k := typ.Kind(); k {
   667  	case Slice:
   668  		slice := jsType(typ).New(srcVal.Get("$array"))
   669  		slice.Set("$offset", srcVal.Get("$offset"))
   670  		slice.Set("$length", srcVal.Get("$length"))
   671  		slice.Set("$capacity", srcVal.Get("$capacity"))
   672  		val = js.Global.Call("$newDataPointer", slice, jsType(PtrTo(typ)))
   673  	case Ptr:
   674  		if typ.Elem().Kind() == Struct {
   675  			if typ.Elem() == v.typ.Elem() {
   676  				val = srcVal
   677  				break
   678  			}
   679  			val = jsType(typ).New()
   680  			copyStruct(val, srcVal, typ.Elem())
   681  			break
   682  		}
   683  		val = jsType(typ).New(srcVal.Get("$get"), srcVal.Get("$set"))
   684  	case Struct:
   685  		val = jsType(typ).Get("ptr").New()
   686  		copyStruct(val, srcVal, typ)
   687  	case Array, Bool, Chan, Func, Interface, Map, String:
   688  		val = js.InternalObject(v.ptr)
   689  	default:
   690  		panic(&ValueError{"reflect.Convert", k})
   691  	}
   692  	return Value{typ.common(), unsafe.Pointer(val.Unsafe()), v.flag.ro() | v.flag&flagIndir | flag(typ.Kind())}
   693  }
   694  
   695  func Copy(dst, src Value) int {
   696  	dk := dst.kind()
   697  	if dk != Array && dk != Slice {
   698  		panic(&ValueError{"reflect.Copy", dk})
   699  	}
   700  	if dk == Array {
   701  		dst.mustBeAssignable()
   702  	}
   703  	dst.mustBeExported()
   704  
   705  	sk := src.kind()
   706  	var stringCopy bool
   707  	if sk != Array && sk != Slice {
   708  		stringCopy = sk == String && dst.typ.Elem().Kind() == Uint8
   709  		if !stringCopy {
   710  			panic(&ValueError{"reflect.Copy", sk})
   711  		}
   712  	}
   713  	src.mustBeExported()
   714  
   715  	if !stringCopy {
   716  		typesMustMatch("reflect.Copy", dst.typ.Elem(), src.typ.Elem())
   717  	}
   718  
   719  	dstVal := dst.object()
   720  	if dk == Array {
   721  		dstVal = jsType(SliceOf(dst.typ.Elem())).New(dstVal)
   722  	}
   723  
   724  	srcVal := src.object()
   725  	if sk == Array {
   726  		srcVal = jsType(SliceOf(src.typ.Elem())).New(srcVal)
   727  	}
   728  
   729  	if stringCopy {
   730  		return js.Global.Call("$copyString", dstVal, srcVal).Int()
   731  	}
   732  	return js.Global.Call("$copySlice", dstVal, srcVal).Int()
   733  }
   734  
   735  func methodReceiver(op string, v Value, i int) (_ *rtype, t *funcType, fn unsafe.Pointer) {
   736  	var prop string
   737  	if v.typ.Kind() == Interface {
   738  		tt := (*interfaceType)(unsafe.Pointer(v.typ))
   739  		if i < 0 || i >= len(tt.methods) {
   740  			panic("reflect: internal error: invalid method index")
   741  		}
   742  		m := &tt.methods[i]
   743  		if !tt.nameOff(m.name).isExported() {
   744  			panic("reflect: " + op + " of unexported method")
   745  		}
   746  		t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
   747  		prop = tt.nameOff(m.name).name()
   748  	} else {
   749  		ms := v.typ.exportedMethods()
   750  		if uint(i) >= uint(len(ms)) {
   751  			panic("reflect: internal error: invalid method index")
   752  		}
   753  		m := ms[i]
   754  		if !v.typ.nameOff(m.name).isExported() {
   755  			panic("reflect: " + op + " of unexported method")
   756  		}
   757  		t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
   758  		prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
   759  	}
   760  	rcvr := v.object()
   761  	if isWrapped(v.typ) {
   762  		rcvr = jsType(v.typ).New(rcvr)
   763  	}
   764  	fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
   765  	return
   766  }
   767  
   768  func valueInterface(v Value, safe bool) interface{} {
   769  	if v.flag == 0 {
   770  		panic(&ValueError{"reflect.Value.Interface", 0})
   771  	}
   772  	if safe && v.flag&flagRO != 0 {
   773  		panic("reflect.Value.Interface: cannot return value obtained from unexported field or method")
   774  	}
   775  	if v.flag&flagMethod != 0 {
   776  		v = makeMethodValue("Interface", v)
   777  	}
   778  	if isWrapped(v.typ) {
   779  		if v.flag&flagIndir != 0 && v.Kind() == Struct {
   780  			cv := jsType(v.typ).Call("zero")
   781  			copyStruct(cv, v.object(), v.typ)
   782  			return interface{}(unsafe.Pointer(jsType(v.typ).New(cv).Unsafe()))
   783  		}
   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  func (t *rtype) pointers() bool {
   814  	switch t.Kind() {
   815  	case Ptr, Map, Chan, Func, Struct, Array:
   816  		return true
   817  	default:
   818  		return false
   819  	}
   820  }
   821  
   822  func (t *rtype) Comparable() bool {
   823  	switch t.Kind() {
   824  	case Func, Slice, Map:
   825  		return false
   826  	case Array:
   827  		return t.Elem().Comparable()
   828  	case Struct:
   829  		for i := 0; i < t.NumField(); i++ {
   830  			if !t.Field(i).Type.Comparable() {
   831  				return false
   832  			}
   833  		}
   834  	}
   835  	return true
   836  }
   837  
   838  func (t *rtype) Method(i int) (m Method) {
   839  	if t.Kind() == Interface {
   840  		tt := (*interfaceType)(unsafe.Pointer(t))
   841  		return tt.Method(i)
   842  	}
   843  	methods := t.exportedMethods()
   844  	if i < 0 || i >= len(methods) {
   845  		panic("reflect: Method index out of range")
   846  	}
   847  	p := methods[i]
   848  	pname := t.nameOff(p.name)
   849  	m.Name = pname.name()
   850  	fl := flag(Func)
   851  	mtyp := t.typeOff(p.mtyp)
   852  	ft := (*funcType)(unsafe.Pointer(mtyp))
   853  	in := make([]Type, 0, 1+len(ft.in()))
   854  	in = append(in, t)
   855  	for _, arg := range ft.in() {
   856  		in = append(in, arg)
   857  	}
   858  	out := make([]Type, 0, len(ft.out()))
   859  	for _, ret := range ft.out() {
   860  		out = append(out, ret)
   861  	}
   862  	mt := FuncOf(in, out, ft.IsVariadic())
   863  	m.Type = mt
   864  	prop := js.Global.Call("$methodSet", js.InternalObject(t).Get("jsType")).Index(i).Get("prop").String()
   865  	fn := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} {
   866  		rcvr := arguments[0]
   867  		return rcvr.Get(prop).Call("apply", rcvr, arguments[1:])
   868  	})
   869  	m.Func = Value{mt.(*rtype), unsafe.Pointer(fn.Unsafe()), fl}
   870  	m.Index = i
   871  	return m
   872  }
   873  
   874  func (v Value) object() *js.Object {
   875  	obj := js.InternalObject(v.ptr)
   876  	kind := v.typ.Kind()
   877  	if kind == Array || kind == Struct {
   878  		return obj
   879  	} else if kind == Ptr && v.typ.Elem().Kind() == Array {
   880  		val := obj.Get("$val")
   881  		if val != js.Undefined {
   882  			return js.InternalObject(val.Unsafe())
   883  		} else {
   884  			return obj
   885  		}
   886  	}
   887  	if v.flag&flagIndir != 0 {
   888  		val := obj.Call("$get")
   889  		if val != js.Global.Get("$ifaceNil") && val.Get("constructor") != jsType(v.typ) {
   890  			switch kind {
   891  			case Uint64, Int64:
   892  				val = jsType(v.typ).New(val.Get("$high"), val.Get("$low"))
   893  			case Complex64, Complex128:
   894  				val = jsType(v.typ).New(val.Get("$real"), val.Get("$imag"))
   895  			case Slice:
   896  				if val == val.Get("constructor").Get("nil") {
   897  					val = jsType(v.typ).Get("nil")
   898  					break
   899  				}
   900  				newVal := jsType(v.typ).New(val.Get("$array"))
   901  				newVal.Set("$offset", val.Get("$offset"))
   902  				newVal.Set("$length", val.Get("$length"))
   903  				newVal.Set("$capacity", val.Get("$capacity"))
   904  				val = newVal
   905  			}
   906  		}
   907  		return js.InternalObject(val.Unsafe())
   908  	}
   909  	return obj
   910  }
   911  
   912  func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
   913  	if v.flag&flagMethod != 0 {
   914  		v = makeMethodValue(context, v)
   915  	}
   916  
   917  	switch {
   918  	case directlyAssignable(dst, v.typ):
   919  		// Overwrite type so that they match.
   920  		// Same memory layout, so no harm done.
   921  		fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
   922  		fl |= flag(dst.Kind())
   923  		return Value{dst, v.ptr, fl}
   924  
   925  	case implements(dst, v.typ):
   926  		if target == nil {
   927  			target = unsafe_New(dst)
   928  		}
   929  		// GopherJS: Skip the v.Kind() == Interface && v.IsNil() if statement
   930  		//           from upstream. ifaceE2I below does not panic, and it needs
   931  		//           to run, given its custom implementation.
   932  		x := valueInterface(v, false)
   933  		if dst.NumMethod() == 0 {
   934  			*(*interface{})(target) = x
   935  		} else {
   936  			ifaceE2I(dst, x, target)
   937  		}
   938  		return Value{dst, target, flagIndir | flag(Interface)}
   939  	}
   940  
   941  	// Failed.
   942  	panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
   943  }
   944  
   945  var callHelper = js.Global.Get("$call").Interface().(func(...interface{}) *js.Object)
   946  
   947  func (v Value) call(op string, in []Value) []Value {
   948  	var (
   949  		t    *funcType
   950  		fn   unsafe.Pointer
   951  		rcvr *js.Object
   952  	)
   953  	if v.flag&flagMethod != 0 {
   954  		_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
   955  		rcvr = v.object()
   956  		if isWrapped(v.typ) {
   957  			rcvr = jsType(v.typ).New(rcvr)
   958  		}
   959  	} else {
   960  		t = (*funcType)(unsafe.Pointer(v.typ))
   961  		fn = unsafe.Pointer(v.object().Unsafe())
   962  		rcvr = js.Undefined
   963  	}
   964  
   965  	if fn == nil {
   966  		panic("reflect.Value.Call: call of nil function")
   967  	}
   968  
   969  	isSlice := op == "CallSlice"
   970  	n := t.NumIn()
   971  	if isSlice {
   972  		if !t.IsVariadic() {
   973  			panic("reflect: CallSlice of non-variadic function")
   974  		}
   975  		if len(in) < n {
   976  			panic("reflect: CallSlice with too few input arguments")
   977  		}
   978  		if len(in) > n {
   979  			panic("reflect: CallSlice with too many input arguments")
   980  		}
   981  	} else {
   982  		if t.IsVariadic() {
   983  			n--
   984  		}
   985  		if len(in) < n {
   986  			panic("reflect: Call with too few input arguments")
   987  		}
   988  		if !t.IsVariadic() && len(in) > n {
   989  			panic("reflect: Call with too many input arguments")
   990  		}
   991  	}
   992  	for _, x := range in {
   993  		if x.Kind() == Invalid {
   994  			panic("reflect: " + op + " using zero Value argument")
   995  		}
   996  	}
   997  	for i := 0; i < n; i++ {
   998  		if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
   999  			panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
  1000  		}
  1001  	}
  1002  	if !isSlice && t.IsVariadic() {
  1003  		// prepare slice for remaining values
  1004  		m := len(in) - n
  1005  		slice := MakeSlice(t.In(n), m, m)
  1006  		elem := t.In(n).Elem()
  1007  		for i := 0; i < m; i++ {
  1008  			x := in[n+i]
  1009  			if xt := x.Type(); !xt.AssignableTo(elem) {
  1010  				panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
  1011  			}
  1012  			slice.Index(i).Set(x)
  1013  		}
  1014  		origIn := in
  1015  		in = make([]Value, n+1)
  1016  		copy(in[:n], origIn)
  1017  		in[n] = slice
  1018  	}
  1019  
  1020  	nin := len(in)
  1021  	if nin != t.NumIn() {
  1022  		panic("reflect.Value.Call: wrong argument count")
  1023  	}
  1024  	nout := t.NumOut()
  1025  
  1026  	argsArray := js.Global.Get("Array").New(t.NumIn())
  1027  	for i, arg := range in {
  1028  		argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
  1029  	}
  1030  	results := callHelper(js.InternalObject(fn), rcvr, argsArray)
  1031  
  1032  	switch nout {
  1033  	case 0:
  1034  		return nil
  1035  	case 1:
  1036  		return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
  1037  	default:
  1038  		ret := make([]Value, nout)
  1039  		for i := range ret {
  1040  			ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
  1041  		}
  1042  		return ret
  1043  	}
  1044  }
  1045  
  1046  func (v Value) Cap() int {
  1047  	k := v.kind()
  1048  	switch k {
  1049  	case Array:
  1050  		return v.typ.Len()
  1051  	case Chan, Slice:
  1052  		return v.object().Get("$capacity").Int()
  1053  	}
  1054  	panic(&ValueError{"reflect.Value.Cap", k})
  1055  }
  1056  
  1057  var jsObjectPtr = reflectType(js.Global.Get("$jsObjectPtr"))
  1058  
  1059  func wrapJsObject(typ Type, val *js.Object) *js.Object {
  1060  	if typ == jsObjectPtr {
  1061  		return jsType(jsObjectPtr).New(val)
  1062  	}
  1063  	return val
  1064  }
  1065  
  1066  func unwrapJsObject(typ Type, val *js.Object) *js.Object {
  1067  	if typ == jsObjectPtr {
  1068  		return val.Get("object")
  1069  	}
  1070  	return val
  1071  }
  1072  
  1073  func (v Value) Elem() Value {
  1074  	switch k := v.kind(); k {
  1075  	case Interface:
  1076  		val := v.object()
  1077  		if val == js.Global.Get("$ifaceNil") {
  1078  			return Value{}
  1079  		}
  1080  		typ := reflectType(val.Get("constructor"))
  1081  		return makeValue(typ, val.Get("$val"), v.flag.ro())
  1082  
  1083  	case Ptr:
  1084  		if v.IsNil() {
  1085  			return Value{}
  1086  		}
  1087  		val := v.object()
  1088  		tt := (*ptrType)(unsafe.Pointer(v.typ))
  1089  		fl := v.flag&flagRO | flagIndir | flagAddr
  1090  		fl |= flag(tt.elem.Kind())
  1091  		return Value{tt.elem, unsafe.Pointer(wrapJsObject(tt.elem, val).Unsafe()), fl}
  1092  
  1093  	default:
  1094  		panic(&ValueError{"reflect.Value.Elem", k})
  1095  	}
  1096  }
  1097  
  1098  func (v Value) Field(i int) Value {
  1099  	if v.kind() != Struct {
  1100  		panic(&ValueError{"reflect.Value.Field", v.kind()})
  1101  	}
  1102  	tt := (*structType)(unsafe.Pointer(v.typ))
  1103  	if uint(i) >= uint(len(tt.fields)) {
  1104  		panic("reflect: Field index out of range")
  1105  	}
  1106  
  1107  	prop := jsType(v.typ).Get("fields").Index(i).Get("prop").String()
  1108  	field := &tt.fields[i]
  1109  	typ := field.typ
  1110  
  1111  	fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
  1112  	if !field.name.isExported() {
  1113  		if field.embedded() {
  1114  			fl |= flagEmbedRO
  1115  		} else {
  1116  			fl |= flagStickyRO
  1117  		}
  1118  	}
  1119  
  1120  	if tag := tt.fields[i].name.tag(); tag != "" && i != 0 {
  1121  		if jsTag := getJsTag(tag); jsTag != "" {
  1122  			for {
  1123  				v = v.Field(0)
  1124  				if v.typ == jsObjectPtr {
  1125  					o := v.object().Get("object")
  1126  					return Value{typ, unsafe.Pointer(jsType(PtrTo(typ)).New(
  1127  						js.InternalObject(func() *js.Object { return js.Global.Call("$internalize", o.Get(jsTag), jsType(typ)) }),
  1128  						js.InternalObject(func(x *js.Object) { o.Set(jsTag, js.Global.Call("$externalize", x, jsType(typ))) }),
  1129  					).Unsafe()), fl}
  1130  				}
  1131  				if v.typ.Kind() == Ptr {
  1132  					v = v.Elem()
  1133  				}
  1134  			}
  1135  		}
  1136  	}
  1137  
  1138  	s := js.InternalObject(v.ptr)
  1139  	if fl&flagIndir != 0 && typ.Kind() != Array && typ.Kind() != Struct {
  1140  		return Value{typ, unsafe.Pointer(jsType(PtrTo(typ)).New(
  1141  			js.InternalObject(func() *js.Object { return wrapJsObject(typ, s.Get(prop)) }),
  1142  			js.InternalObject(func(x *js.Object) { s.Set(prop, unwrapJsObject(typ, x)) }),
  1143  		).Unsafe()), fl}
  1144  	}
  1145  	return makeValue(typ, wrapJsObject(typ, s.Get(prop)), fl)
  1146  }
  1147  
  1148  func getJsTag(tag string) string {
  1149  	for tag != "" {
  1150  		// skip leading space
  1151  		i := 0
  1152  		for i < len(tag) && tag[i] == ' ' {
  1153  			i++
  1154  		}
  1155  		tag = tag[i:]
  1156  		if tag == "" {
  1157  			break
  1158  		}
  1159  
  1160  		// scan to colon.
  1161  		// a space or a quote is a syntax error
  1162  		i = 0
  1163  		for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
  1164  			i++
  1165  		}
  1166  		if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
  1167  			break
  1168  		}
  1169  		name := string(tag[:i])
  1170  		tag = tag[i+1:]
  1171  
  1172  		// scan quoted string to find value
  1173  		i = 1
  1174  		for i < len(tag) && tag[i] != '"' {
  1175  			if tag[i] == '\\' {
  1176  				i++
  1177  			}
  1178  			i++
  1179  		}
  1180  		if i >= len(tag) {
  1181  			break
  1182  		}
  1183  		qvalue := string(tag[:i+1])
  1184  		tag = tag[i+1:]
  1185  
  1186  		if name == "js" {
  1187  			value, _ := strconv.Unquote(qvalue)
  1188  			return value
  1189  		}
  1190  	}
  1191  	return ""
  1192  }
  1193  
  1194  func (v Value) Index(i int) Value {
  1195  	switch k := v.kind(); k {
  1196  	case Array:
  1197  		tt := (*arrayType)(unsafe.Pointer(v.typ))
  1198  		if i < 0 || i > int(tt.len) {
  1199  			panic("reflect: array index out of range")
  1200  		}
  1201  		typ := tt.elem
  1202  		fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind())
  1203  
  1204  		a := js.InternalObject(v.ptr)
  1205  		if fl&flagIndir != 0 && typ.Kind() != Array && typ.Kind() != Struct {
  1206  			return Value{typ, unsafe.Pointer(jsType(PtrTo(typ)).New(
  1207  				js.InternalObject(func() *js.Object { return wrapJsObject(typ, a.Index(i)) }),
  1208  				js.InternalObject(func(x *js.Object) { a.SetIndex(i, unwrapJsObject(typ, x)) }),
  1209  			).Unsafe()), fl}
  1210  		}
  1211  		return makeValue(typ, wrapJsObject(typ, a.Index(i)), fl)
  1212  
  1213  	case Slice:
  1214  		s := v.object()
  1215  		if i < 0 || i >= s.Get("$length").Int() {
  1216  			panic("reflect: slice index out of range")
  1217  		}
  1218  		tt := (*sliceType)(unsafe.Pointer(v.typ))
  1219  		typ := tt.elem
  1220  		fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind())
  1221  
  1222  		i += s.Get("$offset").Int()
  1223  		a := s.Get("$array")
  1224  		if fl&flagIndir != 0 && typ.Kind() != Array && typ.Kind() != Struct {
  1225  			return Value{typ, unsafe.Pointer(jsType(PtrTo(typ)).New(
  1226  				js.InternalObject(func() *js.Object { return wrapJsObject(typ, a.Index(i)) }),
  1227  				js.InternalObject(func(x *js.Object) { a.SetIndex(i, unwrapJsObject(typ, x)) }),
  1228  			).Unsafe()), fl}
  1229  		}
  1230  		return makeValue(typ, wrapJsObject(typ, a.Index(i)), fl)
  1231  
  1232  	case String:
  1233  		str := *(*string)(v.ptr)
  1234  		if i < 0 || i >= len(str) {
  1235  			panic("reflect: string index out of range")
  1236  		}
  1237  		fl := v.flag.ro() | flag(Uint8) | flagIndir
  1238  		c := str[i]
  1239  		return Value{uint8Type, unsafe.Pointer(&c), fl}
  1240  
  1241  	default:
  1242  		panic(&ValueError{"reflect.Value.Index", k})
  1243  	}
  1244  }
  1245  
  1246  func (v Value) InterfaceData() [2]uintptr {
  1247  	panic(errors.New("InterfaceData is not supported by GopherJS"))
  1248  }
  1249  
  1250  func (v Value) IsNil() bool {
  1251  	switch k := v.kind(); k {
  1252  	case Ptr, Slice:
  1253  		return v.object() == jsType(v.typ).Get("nil")
  1254  	case Chan:
  1255  		return v.object() == js.Global.Get("$chanNil")
  1256  	case Func:
  1257  		return v.object() == js.Global.Get("$throwNilPointerError")
  1258  	case Map:
  1259  		return v.object() == js.InternalObject(false)
  1260  	case Interface:
  1261  		return v.object() == js.Global.Get("$ifaceNil")
  1262  	case UnsafePointer:
  1263  		return v.object().Unsafe() == 0
  1264  	default:
  1265  		panic(&ValueError{"reflect.Value.IsNil", k})
  1266  	}
  1267  }
  1268  
  1269  func (v Value) Len() int {
  1270  	switch k := v.kind(); k {
  1271  	case Array, String:
  1272  		return v.object().Length()
  1273  	case Slice:
  1274  		return v.object().Get("$length").Int()
  1275  	case Chan:
  1276  		return v.object().Get("$buffer").Get("length").Int()
  1277  	case Map:
  1278  		return js.Global.Call("$keys", v.object()).Length()
  1279  	default:
  1280  		panic(&ValueError{"reflect.Value.Len", k})
  1281  	}
  1282  }
  1283  
  1284  func (v Value) Pointer() uintptr {
  1285  	switch k := v.kind(); k {
  1286  	case Chan, Map, Ptr, UnsafePointer:
  1287  		if v.IsNil() {
  1288  			return 0
  1289  		}
  1290  		return v.object().Unsafe()
  1291  	case Func:
  1292  		if v.IsNil() {
  1293  			return 0
  1294  		}
  1295  		return 1
  1296  	case Slice:
  1297  		if v.IsNil() {
  1298  			return 0
  1299  		}
  1300  		return v.object().Get("$array").Unsafe()
  1301  	default:
  1302  		panic(&ValueError{"reflect.Value.Pointer", k})
  1303  	}
  1304  }
  1305  
  1306  func (v Value) Set(x Value) {
  1307  	v.mustBeAssignable()
  1308  	x.mustBeExported()
  1309  	x = x.assignTo("reflect.Set", v.typ, nil)
  1310  	if v.flag&flagIndir != 0 {
  1311  		switch v.typ.Kind() {
  1312  		case Array:
  1313  			jsType(v.typ).Call("copy", js.InternalObject(v.ptr), js.InternalObject(x.ptr))
  1314  		case Interface:
  1315  			js.InternalObject(v.ptr).Call("$set", js.InternalObject(valueInterface(x, false)))
  1316  		case Struct:
  1317  			copyStruct(js.InternalObject(v.ptr), js.InternalObject(x.ptr), v.typ)
  1318  		default:
  1319  			js.InternalObject(v.ptr).Call("$set", x.object())
  1320  		}
  1321  		return
  1322  	}
  1323  	v.ptr = x.ptr
  1324  }
  1325  
  1326  func (v Value) SetBytes(x []byte) {
  1327  	v.mustBeAssignable()
  1328  	v.mustBe(Slice)
  1329  	if v.typ.Elem().Kind() != Uint8 {
  1330  		panic("reflect.Value.SetBytes of non-byte slice")
  1331  	}
  1332  	slice := js.InternalObject(x)
  1333  	if v.typ.Name() != "" || v.typ.Elem().Name() != "" {
  1334  		typedSlice := jsType(v.typ).New(slice.Get("$array"))
  1335  		typedSlice.Set("$offset", slice.Get("$offset"))
  1336  		typedSlice.Set("$length", slice.Get("$length"))
  1337  		typedSlice.Set("$capacity", slice.Get("$capacity"))
  1338  		slice = typedSlice
  1339  	}
  1340  	js.InternalObject(v.ptr).Call("$set", slice)
  1341  }
  1342  
  1343  func (v Value) SetCap(n int) {
  1344  	v.mustBeAssignable()
  1345  	v.mustBe(Slice)
  1346  	s := js.InternalObject(v.ptr).Call("$get")
  1347  	if n < s.Get("$length").Int() || n > s.Get("$capacity").Int() {
  1348  		panic("reflect: slice capacity out of range in SetCap")
  1349  	}
  1350  	newSlice := jsType(v.typ).New(s.Get("$array"))
  1351  	newSlice.Set("$offset", s.Get("$offset"))
  1352  	newSlice.Set("$length", s.Get("$length"))
  1353  	newSlice.Set("$capacity", n)
  1354  	js.InternalObject(v.ptr).Call("$set", newSlice)
  1355  }
  1356  
  1357  func (v Value) SetLen(n int) {
  1358  	v.mustBeAssignable()
  1359  	v.mustBe(Slice)
  1360  	s := js.InternalObject(v.ptr).Call("$get")
  1361  	if n < 0 || n > s.Get("$capacity").Int() {
  1362  		panic("reflect: slice length out of range in SetLen")
  1363  	}
  1364  	newSlice := jsType(v.typ).New(s.Get("$array"))
  1365  	newSlice.Set("$offset", s.Get("$offset"))
  1366  	newSlice.Set("$length", n)
  1367  	newSlice.Set("$capacity", s.Get("$capacity"))
  1368  	js.InternalObject(v.ptr).Call("$set", newSlice)
  1369  }
  1370  
  1371  func (v Value) Slice(i, j int) Value {
  1372  	var (
  1373  		cap int
  1374  		typ Type
  1375  		s   *js.Object
  1376  	)
  1377  	switch kind := v.kind(); kind {
  1378  	case Array:
  1379  		if v.flag&flagAddr == 0 {
  1380  			panic("reflect.Value.Slice: slice of unaddressable array")
  1381  		}
  1382  		tt := (*arrayType)(unsafe.Pointer(v.typ))
  1383  		cap = int(tt.len)
  1384  		typ = SliceOf(tt.elem)
  1385  		s = jsType(typ).New(v.object())
  1386  
  1387  	case Slice:
  1388  		typ = v.typ
  1389  		s = v.object()
  1390  		cap = s.Get("$capacity").Int()
  1391  
  1392  	case String:
  1393  		str := *(*string)(v.ptr)
  1394  		if i < 0 || j < i || j > len(str) {
  1395  			panic("reflect.Value.Slice: string slice index out of bounds")
  1396  		}
  1397  		return ValueOf(str[i:j])
  1398  
  1399  	default:
  1400  		panic(&ValueError{"reflect.Value.Slice", kind})
  1401  	}
  1402  
  1403  	if i < 0 || j < i || j > cap {
  1404  		panic("reflect.Value.Slice: slice index out of bounds")
  1405  	}
  1406  
  1407  	return makeValue(typ, js.Global.Call("$subslice", s, i, j), v.flag.ro())
  1408  }
  1409  
  1410  func (v Value) Slice3(i, j, k int) Value {
  1411  	var (
  1412  		cap int
  1413  		typ Type
  1414  		s   *js.Object
  1415  	)
  1416  	switch kind := v.kind(); kind {
  1417  	case Array:
  1418  		if v.flag&flagAddr == 0 {
  1419  			panic("reflect.Value.Slice: slice of unaddressable array")
  1420  		}
  1421  		tt := (*arrayType)(unsafe.Pointer(v.typ))
  1422  		cap = int(tt.len)
  1423  		typ = SliceOf(tt.elem)
  1424  		s = jsType(typ).New(v.object())
  1425  
  1426  	case Slice:
  1427  		typ = v.typ
  1428  		s = v.object()
  1429  		cap = s.Get("$capacity").Int()
  1430  
  1431  	default:
  1432  		panic(&ValueError{"reflect.Value.Slice3", kind})
  1433  	}
  1434  
  1435  	if i < 0 || j < i || k < j || k > cap {
  1436  		panic("reflect.Value.Slice3: slice index out of bounds")
  1437  	}
  1438  
  1439  	return makeValue(typ, js.Global.Call("$subslice", s, i, j, k), v.flag.ro())
  1440  }
  1441  
  1442  func (v Value) Close() {
  1443  	v.mustBe(Chan)
  1444  	v.mustBeExported()
  1445  	js.Global.Call("$close", v.object())
  1446  }
  1447  
  1448  var selectHelper = js.Global.Get("$select").Interface().(func(...interface{}) *js.Object)
  1449  
  1450  func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool) {
  1451  	comms := [][]*js.Object{{js.InternalObject(ch)}}
  1452  	if nb {
  1453  		comms = append(comms, []*js.Object{})
  1454  	}
  1455  	selectRes := selectHelper(comms)
  1456  	if nb && selectRes.Index(0).Int() == 1 {
  1457  		return false, false
  1458  	}
  1459  	recvRes := selectRes.Index(1)
  1460  	js.InternalObject(val).Call("$set", recvRes.Index(0))
  1461  	return true, recvRes.Index(1).Bool()
  1462  }
  1463  
  1464  func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool {
  1465  	comms := [][]*js.Object{{js.InternalObject(ch), js.InternalObject(val).Call("$get")}}
  1466  	if nb {
  1467  		comms = append(comms, []*js.Object{})
  1468  	}
  1469  	selectRes := selectHelper(comms)
  1470  	if nb && selectRes.Index(0).Int() == 1 {
  1471  		return false
  1472  	}
  1473  	return true
  1474  }
  1475  
  1476  func rselect(rselects []runtimeSelect) (chosen int, recvOK bool) {
  1477  	comms := make([][]*js.Object, len(rselects))
  1478  	for i, s := range rselects {
  1479  		switch SelectDir(s.dir) {
  1480  		case SelectDefault:
  1481  			comms[i] = []*js.Object{}
  1482  		case SelectRecv:
  1483  			ch := js.Global.Get("$chanNil")
  1484  			if js.InternalObject(s.ch) != js.InternalObject(0) {
  1485  				ch = js.InternalObject(s.ch)
  1486  			}
  1487  			comms[i] = []*js.Object{ch}
  1488  		case SelectSend:
  1489  			ch := js.Global.Get("$chanNil")
  1490  			var val *js.Object
  1491  			if js.InternalObject(s.ch) != js.InternalObject(0) {
  1492  				ch = js.InternalObject(s.ch)
  1493  				val = js.InternalObject(s.val).Call("$get")
  1494  			}
  1495  			comms[i] = []*js.Object{ch, val}
  1496  		}
  1497  	}
  1498  	selectRes := selectHelper(comms)
  1499  	c := selectRes.Index(0).Int()
  1500  	if SelectDir(rselects[c].dir) == SelectRecv {
  1501  		recvRes := selectRes.Index(1)
  1502  		js.InternalObject(rselects[c].val).Call("$set", recvRes.Index(0))
  1503  		return c, recvRes.Index(1).Bool()
  1504  	}
  1505  	return c, false
  1506  }
  1507  
  1508  func DeepEqual(a1, a2 interface{}) bool {
  1509  	i1 := js.InternalObject(a1)
  1510  	i2 := js.InternalObject(a2)
  1511  	if i1 == i2 {
  1512  		return true
  1513  	}
  1514  	if i1 == nil || i2 == nil || i1.Get("constructor") != i2.Get("constructor") {
  1515  		return false
  1516  	}
  1517  	return deepValueEqualJs(ValueOf(a1), ValueOf(a2), nil)
  1518  }
  1519  
  1520  func deepValueEqualJs(v1, v2 Value, visited [][2]unsafe.Pointer) bool {
  1521  	if !v1.IsValid() || !v2.IsValid() {
  1522  		return !v1.IsValid() && !v2.IsValid()
  1523  	}
  1524  	if v1.Type() != v2.Type() {
  1525  		return false
  1526  	}
  1527  	if v1.Type() == jsObjectPtr {
  1528  		return unwrapJsObject(jsObjectPtr, v1.object()) == unwrapJsObject(jsObjectPtr, v2.object())
  1529  	}
  1530  
  1531  	switch v1.Kind() {
  1532  	case Array, Map, Slice, Struct:
  1533  		for _, entry := range visited {
  1534  			if v1.ptr == entry[0] && v2.ptr == entry[1] {
  1535  				return true
  1536  			}
  1537  		}
  1538  		visited = append(visited, [2]unsafe.Pointer{v1.ptr, v2.ptr})
  1539  	}
  1540  
  1541  	switch v1.Kind() {
  1542  	case Array, Slice:
  1543  		if v1.Kind() == Slice {
  1544  			if v1.IsNil() != v2.IsNil() {
  1545  				return false
  1546  			}
  1547  			if v1.object() == v2.object() {
  1548  				return true
  1549  			}
  1550  		}
  1551  		var n = v1.Len()
  1552  		if n != v2.Len() {
  1553  			return false
  1554  		}
  1555  		for i := 0; i < n; i++ {
  1556  			if !deepValueEqualJs(v1.Index(i), v2.Index(i), visited) {
  1557  				return false
  1558  			}
  1559  		}
  1560  		return true
  1561  	case Interface:
  1562  		if v1.IsNil() || v2.IsNil() {
  1563  			return v1.IsNil() && v2.IsNil()
  1564  		}
  1565  		return deepValueEqualJs(v1.Elem(), v2.Elem(), visited)
  1566  	case Ptr:
  1567  		return deepValueEqualJs(v1.Elem(), v2.Elem(), visited)
  1568  	case Struct:
  1569  		var n = v1.NumField()
  1570  		for i := 0; i < n; i++ {
  1571  			if !deepValueEqualJs(v1.Field(i), v2.Field(i), visited) {
  1572  				return false
  1573  			}
  1574  		}
  1575  		return true
  1576  	case Map:
  1577  		if v1.IsNil() != v2.IsNil() {
  1578  			return false
  1579  		}
  1580  		if v1.object() == v2.object() {
  1581  			return true
  1582  		}
  1583  		var keys = v1.MapKeys()
  1584  		if len(keys) != v2.Len() {
  1585  			return false
  1586  		}
  1587  		for _, k := range keys {
  1588  			val1 := v1.MapIndex(k)
  1589  			val2 := v2.MapIndex(k)
  1590  			if !val1.IsValid() || !val2.IsValid() || !deepValueEqualJs(val1, val2, visited) {
  1591  				return false
  1592  			}
  1593  		}
  1594  		return true
  1595  	case Func:
  1596  		return v1.IsNil() && v2.IsNil()
  1597  	case UnsafePointer:
  1598  		return v1.object() == v2.object()
  1599  	}
  1600  
  1601  	return js.Global.Call("$interfaceIsEqual", js.InternalObject(valueInterface(v1, false)), js.InternalObject(valueInterface(v2, false))).Bool()
  1602  }