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  }