github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/typedarrays.go (about)

     1  package goja
     2  
     3  import (
     4  	"math"
     5  	"reflect"
     6  	"strconv"
     7  	"unsafe"
     8  
     9  	"github.com/nuvolaris/goja/unistring"
    10  )
    11  
    12  type byteOrder bool
    13  
    14  const (
    15  	bigEndian    byteOrder = false
    16  	littleEndian byteOrder = true
    17  )
    18  
    19  var (
    20  	nativeEndian byteOrder
    21  
    22  	arrayBufferType = reflect.TypeOf(ArrayBuffer{})
    23  )
    24  
    25  type typedArrayObjectCtor func(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject
    26  
    27  type arrayBufferObject struct {
    28  	baseObject
    29  	detached bool
    30  	data     []byte
    31  }
    32  
    33  // ArrayBuffer is a Go wrapper around ECMAScript ArrayBuffer. Calling Runtime.ToValue() on it
    34  // returns the underlying ArrayBuffer. Calling Export() on an ECMAScript ArrayBuffer returns a wrapper.
    35  // Use Runtime.NewArrayBuffer([]byte) to create one.
    36  type ArrayBuffer struct {
    37  	buf *arrayBufferObject
    38  }
    39  
    40  type dataViewObject struct {
    41  	baseObject
    42  	viewedArrayBuf      *arrayBufferObject
    43  	byteLen, byteOffset int
    44  }
    45  
    46  type typedArray interface {
    47  	toRaw(Value) uint64
    48  	get(idx int) Value
    49  	set(idx int, value Value)
    50  	getRaw(idx int) uint64
    51  	setRaw(idx int, raw uint64)
    52  	less(i, j int) bool
    53  	swap(i, j int)
    54  	typeMatch(v Value) bool
    55  	export(offset int, length int) interface{}
    56  	exportType() reflect.Type
    57  }
    58  
    59  type uint8Array []byte
    60  type uint8ClampedArray []byte
    61  type int8Array []byte
    62  type uint16Array []byte
    63  type int16Array []byte
    64  type uint32Array []byte
    65  type int32Array []byte
    66  type float32Array []byte
    67  type float64Array []byte
    68  
    69  type typedArrayObject struct {
    70  	baseObject
    71  	viewedArrayBuf *arrayBufferObject
    72  	defaultCtor    *Object
    73  	length, offset int
    74  	elemSize       int
    75  	typedArray     typedArray
    76  }
    77  
    78  func (a ArrayBuffer) toValue(r *Runtime) Value {
    79  	if a.buf == nil {
    80  		return _null
    81  	}
    82  	v := a.buf.val
    83  	if v.runtime != r {
    84  		panic(r.NewTypeError("Illegal runtime transition of an ArrayBuffer"))
    85  	}
    86  	return v
    87  }
    88  
    89  // Bytes returns the underlying []byte for this ArrayBuffer.
    90  // For detached ArrayBuffers returns nil.
    91  func (a ArrayBuffer) Bytes() []byte {
    92  	return a.buf.data
    93  }
    94  
    95  // Detach the ArrayBuffer. After this, the underlying []byte becomes unreferenced and any attempt
    96  // to use this ArrayBuffer results in a TypeError.
    97  // Returns false if it was already detached, true otherwise.
    98  // Note, this method may only be called from the goroutine that 'owns' the Runtime, it may not
    99  // be called concurrently.
   100  func (a ArrayBuffer) Detach() bool {
   101  	if a.buf.detached {
   102  		return false
   103  	}
   104  	a.buf.detach()
   105  	return true
   106  }
   107  
   108  // Detached returns true if the ArrayBuffer is detached.
   109  func (a ArrayBuffer) Detached() bool {
   110  	return a.buf.detached
   111  }
   112  
   113  // NewArrayBuffer creates a new instance of ArrayBuffer backed by the provided byte slice.
   114  //
   115  // Warning: be careful when using unaligned slices (sub-slices that do not start at word boundaries). If later a
   116  // typed array of a multibyte type (uint16, uint32, etc.) is created from a buffer backed by an unaligned slice,
   117  // using this typed array will result in unaligned access which may cause performance degradation or runtime panics
   118  // on some architectures or configurations.
   119  func (r *Runtime) NewArrayBuffer(data []byte) ArrayBuffer {
   120  	buf := r._newArrayBuffer(r.global.ArrayBufferPrototype, nil)
   121  	buf.data = data
   122  	return ArrayBuffer{
   123  		buf: buf,
   124  	}
   125  }
   126  
   127  func (a *uint8Array) toRaw(v Value) uint64 {
   128  	return uint64(toUint8(v))
   129  }
   130  
   131  func (a *uint8Array) ptr(idx int) *uint8 {
   132  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   133  	return (*uint8)(unsafe.Pointer(uintptr(p) + uintptr(idx)))
   134  }
   135  
   136  func (a *uint8Array) get(idx int) Value {
   137  	return intToValue(int64(*(a.ptr(idx))))
   138  }
   139  
   140  func (a *uint8Array) set(idx int, value Value) {
   141  	*(a.ptr(idx)) = toUint8(value)
   142  }
   143  
   144  func (a *uint8Array) getRaw(idx int) uint64 {
   145  	return uint64(*(a.ptr(idx)))
   146  }
   147  
   148  func (a *uint8Array) setRaw(idx int, raw uint64) {
   149  	*(a.ptr(idx)) = uint8(raw)
   150  }
   151  
   152  func (a *uint8Array) less(i, j int) bool {
   153  	return *(a.ptr(i)) < *(a.ptr(j))
   154  }
   155  
   156  func (a *uint8Array) swap(i, j int) {
   157  	pi, pj := a.ptr(i), a.ptr(j)
   158  	*pi, *pj = *pj, *pi
   159  }
   160  
   161  func (a *uint8Array) typeMatch(v Value) bool {
   162  	if i, ok := v.(valueInt); ok {
   163  		return i >= 0 && i <= 255
   164  	}
   165  	return false
   166  }
   167  
   168  func (a *uint8Array) export(offset int, length int) interface{} {
   169  	return ([]uint8)(*a)[offset : offset+length : offset+length]
   170  }
   171  
   172  func (a *uint8Array) exportType() reflect.Type {
   173  	return typeBytes
   174  }
   175  
   176  func (a *uint8ClampedArray) toRaw(v Value) uint64 {
   177  	return uint64(toUint8Clamp(v))
   178  }
   179  
   180  func (a *uint8ClampedArray) ptr(idx int) *uint8 {
   181  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   182  	return (*uint8)(unsafe.Pointer(uintptr(p) + uintptr(idx)))
   183  }
   184  
   185  func (a *uint8ClampedArray) get(idx int) Value {
   186  	return intToValue(int64(*(a.ptr(idx))))
   187  }
   188  
   189  func (a *uint8ClampedArray) set(idx int, value Value) {
   190  	*(a.ptr(idx)) = toUint8Clamp(value)
   191  }
   192  
   193  func (a *uint8ClampedArray) getRaw(idx int) uint64 {
   194  	return uint64(*(a.ptr(idx)))
   195  }
   196  
   197  func (a *uint8ClampedArray) setRaw(idx int, raw uint64) {
   198  	*(a.ptr(idx)) = uint8(raw)
   199  }
   200  
   201  func (a *uint8ClampedArray) less(i, j int) bool {
   202  	return *(a.ptr(i)) < *(a.ptr(j))
   203  }
   204  
   205  func (a *uint8ClampedArray) swap(i, j int) {
   206  	pi, pj := a.ptr(i), a.ptr(j)
   207  	*pi, *pj = *pj, *pi
   208  }
   209  
   210  func (a *uint8ClampedArray) typeMatch(v Value) bool {
   211  	if i, ok := v.(valueInt); ok {
   212  		return i >= 0 && i <= 255
   213  	}
   214  	return false
   215  }
   216  
   217  func (a *uint8ClampedArray) export(offset int, length int) interface{} {
   218  	return ([]uint8)(*a)[offset : offset+length : offset+length]
   219  }
   220  
   221  func (a *uint8ClampedArray) exportType() reflect.Type {
   222  	return typeBytes
   223  }
   224  
   225  func (a *int8Array) ptr(idx int) *int8 {
   226  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   227  	return (*int8)(unsafe.Pointer(uintptr(p) + uintptr(idx)))
   228  }
   229  
   230  func (a *int8Array) get(idx int) Value {
   231  	return intToValue(int64(*(a.ptr(idx))))
   232  }
   233  
   234  func (a *int8Array) getRaw(idx int) uint64 {
   235  	return uint64(*(a.ptr(idx)))
   236  }
   237  
   238  func (a *int8Array) set(idx int, value Value) {
   239  	*(a.ptr(idx)) = toInt8(value)
   240  }
   241  
   242  func (a *int8Array) toRaw(v Value) uint64 {
   243  	return uint64(toInt8(v))
   244  }
   245  
   246  func (a *int8Array) setRaw(idx int, v uint64) {
   247  	*(a.ptr(idx)) = int8(v)
   248  }
   249  
   250  func (a *int8Array) less(i, j int) bool {
   251  	return *(a.ptr(i)) < *(a.ptr(j))
   252  }
   253  
   254  func (a *int8Array) swap(i, j int) {
   255  	pi, pj := a.ptr(i), a.ptr(j)
   256  	*pi, *pj = *pj, *pi
   257  }
   258  
   259  func (a *int8Array) typeMatch(v Value) bool {
   260  	if i, ok := v.(valueInt); ok {
   261  		return i >= math.MinInt8 && i <= math.MaxInt8
   262  	}
   263  	return false
   264  }
   265  
   266  func (a *int8Array) export(offset int, length int) interface{} {
   267  	var res []int8
   268  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   269  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)
   270  	sliceHeader.Len = length
   271  	sliceHeader.Cap = length
   272  	return res
   273  }
   274  
   275  var typeInt8Array = reflect.TypeOf(([]int8)(nil))
   276  
   277  func (a *int8Array) exportType() reflect.Type {
   278  	return typeInt8Array
   279  }
   280  
   281  func (a *uint16Array) toRaw(v Value) uint64 {
   282  	return uint64(toUint16(v))
   283  }
   284  
   285  func (a *uint16Array) ptr(idx int) *uint16 {
   286  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   287  	return (*uint16)(unsafe.Pointer(uintptr(p) + uintptr(idx)*2))
   288  }
   289  
   290  func (a *uint16Array) get(idx int) Value {
   291  	return intToValue(int64(*(a.ptr(idx))))
   292  }
   293  
   294  func (a *uint16Array) set(idx int, value Value) {
   295  	*(a.ptr(idx)) = toUint16(value)
   296  }
   297  
   298  func (a *uint16Array) getRaw(idx int) uint64 {
   299  	return uint64(*(a.ptr(idx)))
   300  }
   301  
   302  func (a *uint16Array) setRaw(idx int, raw uint64) {
   303  	*(a.ptr(idx)) = uint16(raw)
   304  }
   305  
   306  func (a *uint16Array) less(i, j int) bool {
   307  	return *(a.ptr(i)) < *(a.ptr(j))
   308  }
   309  
   310  func (a *uint16Array) swap(i, j int) {
   311  	pi, pj := a.ptr(i), a.ptr(j)
   312  	*pi, *pj = *pj, *pi
   313  }
   314  
   315  func (a *uint16Array) typeMatch(v Value) bool {
   316  	if i, ok := v.(valueInt); ok {
   317  		return i >= 0 && i <= math.MaxUint16
   318  	}
   319  	return false
   320  }
   321  
   322  var typeUint16Array = reflect.TypeOf(([]uint16)(nil))
   323  
   324  func (a *uint16Array) export(offset int, length int) interface{} {
   325  	var res []uint16
   326  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   327  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*2
   328  	sliceHeader.Len = length
   329  	sliceHeader.Cap = length
   330  	return res
   331  }
   332  
   333  func (a *uint16Array) exportType() reflect.Type {
   334  	return typeUint16Array
   335  }
   336  
   337  func (a *int16Array) ptr(idx int) *int16 {
   338  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   339  	return (*int16)(unsafe.Pointer(uintptr(p) + uintptr(idx)*2))
   340  }
   341  
   342  func (a *int16Array) get(idx int) Value {
   343  	return intToValue(int64(*(a.ptr(idx))))
   344  }
   345  
   346  func (a *int16Array) getRaw(idx int) uint64 {
   347  	return uint64(*(a.ptr(idx)))
   348  }
   349  
   350  func (a *int16Array) set(idx int, value Value) {
   351  	*(a.ptr(idx)) = toInt16(value)
   352  }
   353  
   354  func (a *int16Array) toRaw(v Value) uint64 {
   355  	return uint64(toInt16(v))
   356  }
   357  
   358  func (a *int16Array) setRaw(idx int, v uint64) {
   359  	*(a.ptr(idx)) = int16(v)
   360  }
   361  
   362  func (a *int16Array) less(i, j int) bool {
   363  	return *(a.ptr(i)) < *(a.ptr(j))
   364  }
   365  
   366  func (a *int16Array) swap(i, j int) {
   367  	pi, pj := a.ptr(i), a.ptr(j)
   368  	*pi, *pj = *pj, *pi
   369  }
   370  
   371  func (a *int16Array) typeMatch(v Value) bool {
   372  	if i, ok := v.(valueInt); ok {
   373  		return i >= math.MinInt16 && i <= math.MaxInt16
   374  	}
   375  	return false
   376  }
   377  
   378  func (a *int16Array) export(offset int, length int) interface{} {
   379  	var res []int16
   380  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   381  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*2
   382  	sliceHeader.Len = length
   383  	sliceHeader.Cap = length
   384  	return res
   385  }
   386  
   387  var typeInt16Array = reflect.TypeOf(([]int16)(nil))
   388  
   389  func (a *int16Array) exportType() reflect.Type {
   390  	return typeInt16Array
   391  }
   392  
   393  func (a *uint32Array) ptr(idx int) *uint32 {
   394  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   395  	return (*uint32)(unsafe.Pointer(uintptr(p) + uintptr(idx)*4))
   396  }
   397  
   398  func (a *uint32Array) get(idx int) Value {
   399  	return intToValue(int64(*(a.ptr(idx))))
   400  }
   401  
   402  func (a *uint32Array) getRaw(idx int) uint64 {
   403  	return uint64(*(a.ptr(idx)))
   404  }
   405  
   406  func (a *uint32Array) set(idx int, value Value) {
   407  	*(a.ptr(idx)) = toUint32(value)
   408  }
   409  
   410  func (a *uint32Array) toRaw(v Value) uint64 {
   411  	return uint64(toUint32(v))
   412  }
   413  
   414  func (a *uint32Array) setRaw(idx int, v uint64) {
   415  	*(a.ptr(idx)) = uint32(v)
   416  }
   417  
   418  func (a *uint32Array) less(i, j int) bool {
   419  	return *(a.ptr(i)) < *(a.ptr(j))
   420  }
   421  
   422  func (a *uint32Array) swap(i, j int) {
   423  	pi, pj := a.ptr(i), a.ptr(j)
   424  	*pi, *pj = *pj, *pi
   425  }
   426  
   427  func (a *uint32Array) typeMatch(v Value) bool {
   428  	if i, ok := v.(valueInt); ok {
   429  		return i >= 0 && i <= math.MaxUint32
   430  	}
   431  	return false
   432  }
   433  
   434  func (a *uint32Array) export(offset int, length int) interface{} {
   435  	var res []uint32
   436  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   437  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*4
   438  	sliceHeader.Len = length
   439  	sliceHeader.Cap = length
   440  	return res
   441  }
   442  
   443  var typeUint32Array = reflect.TypeOf(([]uint32)(nil))
   444  
   445  func (a *uint32Array) exportType() reflect.Type {
   446  	return typeUint32Array
   447  }
   448  
   449  func (a *int32Array) ptr(idx int) *int32 {
   450  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   451  	return (*int32)(unsafe.Pointer(uintptr(p) + uintptr(idx)*4))
   452  }
   453  
   454  func (a *int32Array) get(idx int) Value {
   455  	return intToValue(int64(*(a.ptr(idx))))
   456  }
   457  
   458  func (a *int32Array) getRaw(idx int) uint64 {
   459  	return uint64(*(a.ptr(idx)))
   460  }
   461  
   462  func (a *int32Array) set(idx int, value Value) {
   463  	*(a.ptr(idx)) = toInt32(value)
   464  }
   465  
   466  func (a *int32Array) toRaw(v Value) uint64 {
   467  	return uint64(toInt32(v))
   468  }
   469  
   470  func (a *int32Array) setRaw(idx int, v uint64) {
   471  	*(a.ptr(idx)) = int32(v)
   472  }
   473  
   474  func (a *int32Array) less(i, j int) bool {
   475  	return *(a.ptr(i)) < *(a.ptr(j))
   476  }
   477  
   478  func (a *int32Array) swap(i, j int) {
   479  	pi, pj := a.ptr(i), a.ptr(j)
   480  	*pi, *pj = *pj, *pi
   481  }
   482  
   483  func (a *int32Array) typeMatch(v Value) bool {
   484  	if i, ok := v.(valueInt); ok {
   485  		return i >= math.MinInt32 && i <= math.MaxInt32
   486  	}
   487  	return false
   488  }
   489  
   490  func (a *int32Array) export(offset int, length int) interface{} {
   491  	var res []int32
   492  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   493  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*4
   494  	sliceHeader.Len = length
   495  	sliceHeader.Cap = length
   496  	return res
   497  }
   498  
   499  var typeInt32Array = reflect.TypeOf(([]int32)(nil))
   500  
   501  func (a *int32Array) exportType() reflect.Type {
   502  	return typeInt32Array
   503  }
   504  
   505  func (a *float32Array) ptr(idx int) *float32 {
   506  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   507  	return (*float32)(unsafe.Pointer(uintptr(p) + uintptr(idx)*4))
   508  }
   509  
   510  func (a *float32Array) get(idx int) Value {
   511  	return floatToValue(float64(*(a.ptr(idx))))
   512  }
   513  
   514  func (a *float32Array) getRaw(idx int) uint64 {
   515  	return uint64(math.Float32bits(*(a.ptr(idx))))
   516  }
   517  
   518  func (a *float32Array) set(idx int, value Value) {
   519  	*(a.ptr(idx)) = toFloat32(value)
   520  }
   521  
   522  func (a *float32Array) toRaw(v Value) uint64 {
   523  	return uint64(math.Float32bits(toFloat32(v)))
   524  }
   525  
   526  func (a *float32Array) setRaw(idx int, v uint64) {
   527  	*(a.ptr(idx)) = math.Float32frombits(uint32(v))
   528  }
   529  
   530  func typedFloatLess(x, y float64) bool {
   531  	xNan := math.IsNaN(x)
   532  	yNan := math.IsNaN(y)
   533  	if yNan {
   534  		return !xNan
   535  	} else if xNan {
   536  		return false
   537  	}
   538  	if x == 0 && y == 0 { // handle neg zero
   539  		return math.Signbit(x)
   540  	}
   541  	return x < y
   542  }
   543  
   544  func (a *float32Array) less(i, j int) bool {
   545  	return typedFloatLess(float64(*(a.ptr(i))), float64(*(a.ptr(j))))
   546  }
   547  
   548  func (a *float32Array) swap(i, j int) {
   549  	pi, pj := a.ptr(i), a.ptr(j)
   550  	*pi, *pj = *pj, *pi
   551  }
   552  
   553  func (a *float32Array) typeMatch(v Value) bool {
   554  	switch v.(type) {
   555  	case valueInt, valueFloat:
   556  		return true
   557  	}
   558  	return false
   559  }
   560  
   561  func (a *float32Array) export(offset int, length int) interface{} {
   562  	var res []float32
   563  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   564  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*4
   565  	sliceHeader.Len = length
   566  	sliceHeader.Cap = length
   567  	return res
   568  }
   569  
   570  var typeFloat32Array = reflect.TypeOf(([]float32)(nil))
   571  
   572  func (a *float32Array) exportType() reflect.Type {
   573  	return typeFloat32Array
   574  }
   575  
   576  func (a *float64Array) ptr(idx int) *float64 {
   577  	p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(a)).Data)
   578  	return (*float64)(unsafe.Pointer(uintptr(p) + uintptr(idx)*8))
   579  }
   580  
   581  func (a *float64Array) get(idx int) Value {
   582  	return floatToValue(*(a.ptr(idx)))
   583  }
   584  
   585  func (a *float64Array) getRaw(idx int) uint64 {
   586  	return math.Float64bits(*(a.ptr(idx)))
   587  }
   588  
   589  func (a *float64Array) set(idx int, value Value) {
   590  	*(a.ptr(idx)) = value.ToFloat()
   591  }
   592  
   593  func (a *float64Array) toRaw(v Value) uint64 {
   594  	return math.Float64bits(v.ToFloat())
   595  }
   596  
   597  func (a *float64Array) setRaw(idx int, v uint64) {
   598  	*(a.ptr(idx)) = math.Float64frombits(v)
   599  }
   600  
   601  func (a *float64Array) less(i, j int) bool {
   602  	return typedFloatLess(*(a.ptr(i)), *(a.ptr(j)))
   603  }
   604  
   605  func (a *float64Array) swap(i, j int) {
   606  	pi, pj := a.ptr(i), a.ptr(j)
   607  	*pi, *pj = *pj, *pi
   608  }
   609  
   610  func (a *float64Array) typeMatch(v Value) bool {
   611  	switch v.(type) {
   612  	case valueInt, valueFloat:
   613  		return true
   614  	}
   615  	return false
   616  }
   617  
   618  func (a *float64Array) export(offset int, length int) interface{} {
   619  	var res []float64
   620  	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&res))
   621  	sliceHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(a)).Data + uintptr(offset)*8
   622  	sliceHeader.Len = length
   623  	sliceHeader.Cap = length
   624  	return res
   625  }
   626  
   627  var typeFloat64Array = reflect.TypeOf(([]float64)(nil))
   628  
   629  func (a *float64Array) exportType() reflect.Type {
   630  	return typeFloat64Array
   631  }
   632  
   633  func (a *typedArrayObject) _getIdx(idx int) Value {
   634  	if 0 <= idx && idx < a.length {
   635  		if !a.viewedArrayBuf.ensureNotDetached(false) {
   636  			return nil
   637  		}
   638  		return a.typedArray.get(idx + a.offset)
   639  	}
   640  	return nil
   641  }
   642  
   643  func (a *typedArrayObject) getOwnPropStr(name unistring.String) Value {
   644  	idx, ok := strToIntNum(name)
   645  	if ok {
   646  		v := a._getIdx(idx)
   647  		if v != nil {
   648  			return &valueProperty{
   649  				value:        v,
   650  				writable:     true,
   651  				enumerable:   true,
   652  				configurable: true,
   653  			}
   654  		}
   655  		return nil
   656  	}
   657  	if idx == 0 {
   658  		return nil
   659  	}
   660  	return a.baseObject.getOwnPropStr(name)
   661  }
   662  
   663  func (a *typedArrayObject) getOwnPropIdx(idx valueInt) Value {
   664  	v := a._getIdx(toIntClamp(int64(idx)))
   665  	if v != nil {
   666  		return &valueProperty{
   667  			value:        v,
   668  			writable:     true,
   669  			enumerable:   true,
   670  			configurable: true,
   671  		}
   672  	}
   673  	return nil
   674  }
   675  
   676  func (a *typedArrayObject) getStr(name unistring.String, receiver Value) Value {
   677  	idx, ok := strToIntNum(name)
   678  	if ok {
   679  		return a._getIdx(idx)
   680  	}
   681  	if idx == 0 {
   682  		return nil
   683  	}
   684  	return a.baseObject.getStr(name, receiver)
   685  }
   686  
   687  func (a *typedArrayObject) getIdx(idx valueInt, receiver Value) Value {
   688  	return a._getIdx(toIntClamp(int64(idx)))
   689  }
   690  
   691  func (a *typedArrayObject) isValidIntegerIndex(idx int) bool {
   692  	if a.viewedArrayBuf.ensureNotDetached(false) {
   693  		if idx >= 0 && idx < a.length {
   694  			return true
   695  		}
   696  	}
   697  	return false
   698  }
   699  
   700  func (a *typedArrayObject) _putIdx(idx int, v Value) {
   701  	v = v.ToNumber()
   702  	if a.isValidIntegerIndex(idx) {
   703  		a.typedArray.set(idx+a.offset, v)
   704  	}
   705  }
   706  
   707  func (a *typedArrayObject) _hasIdx(idx int) bool {
   708  	return a.isValidIntegerIndex(idx)
   709  }
   710  
   711  func (a *typedArrayObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
   712  	idx, ok := strToIntNum(p)
   713  	if ok {
   714  		a._putIdx(idx, v)
   715  		return true
   716  	}
   717  	if idx == 0 {
   718  		v.ToNumber() // make sure it throws
   719  		return true
   720  	}
   721  	return a.baseObject.setOwnStr(p, v, throw)
   722  }
   723  
   724  func (a *typedArrayObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
   725  	a._putIdx(toIntClamp(int64(p)), v)
   726  	return true
   727  }
   728  
   729  func (a *typedArrayObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
   730  	return a._setForeignStr(p, a.getOwnPropStr(p), v, receiver, throw)
   731  }
   732  
   733  func (a *typedArrayObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
   734  	return a._setForeignIdx(p, trueValIfPresent(a.hasOwnPropertyIdx(p)), v, receiver, throw)
   735  }
   736  
   737  func (a *typedArrayObject) hasOwnPropertyStr(name unistring.String) bool {
   738  	idx, ok := strToIntNum(name)
   739  	if ok {
   740  		return a._hasIdx(idx)
   741  	}
   742  	if idx == 0 {
   743  		return false
   744  	}
   745  	return a.baseObject.hasOwnPropertyStr(name)
   746  }
   747  
   748  func (a *typedArrayObject) hasOwnPropertyIdx(idx valueInt) bool {
   749  	return a._hasIdx(toIntClamp(int64(idx)))
   750  }
   751  
   752  func (a *typedArrayObject) hasPropertyStr(name unistring.String) bool {
   753  	idx, ok := strToIntNum(name)
   754  	if ok {
   755  		return a._hasIdx(idx)
   756  	}
   757  	if idx == 0 {
   758  		return false
   759  	}
   760  	return a.baseObject.hasPropertyStr(name)
   761  }
   762  
   763  func (a *typedArrayObject) hasPropertyIdx(idx valueInt) bool {
   764  	return a.hasOwnPropertyIdx(idx)
   765  }
   766  
   767  func (a *typedArrayObject) _defineIdxProperty(idx int, desc PropertyDescriptor, throw bool) bool {
   768  	if desc.Configurable == FLAG_FALSE || desc.Enumerable == FLAG_FALSE || desc.IsAccessor() || desc.Writable == FLAG_FALSE {
   769  		a.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", idx)
   770  		return false
   771  	}
   772  	_, ok := a._defineOwnProperty(unistring.String(strconv.Itoa(idx)), a.getOwnPropIdx(valueInt(idx)), desc, throw)
   773  	if ok {
   774  		if !a.isValidIntegerIndex(idx) {
   775  			a.val.runtime.typeErrorResult(throw, "Invalid typed array index")
   776  			return false
   777  		}
   778  		a._putIdx(idx, desc.Value)
   779  		return true
   780  	}
   781  	return ok
   782  }
   783  
   784  func (a *typedArrayObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
   785  	idx, ok := strToIntNum(name)
   786  	if ok {
   787  		return a._defineIdxProperty(idx, desc, throw)
   788  	}
   789  	if idx == 0 {
   790  		a.viewedArrayBuf.ensureNotDetached(throw)
   791  		a.val.runtime.typeErrorResult(throw, "Invalid typed array index")
   792  		return false
   793  	}
   794  	return a.baseObject.defineOwnPropertyStr(name, desc, throw)
   795  }
   796  
   797  func (a *typedArrayObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
   798  	return a._defineIdxProperty(toIntClamp(int64(name)), desc, throw)
   799  }
   800  
   801  func (a *typedArrayObject) deleteStr(name unistring.String, throw bool) bool {
   802  	idx, ok := strToIntNum(name)
   803  	if ok {
   804  		if a.isValidIntegerIndex(idx) {
   805  			a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String())
   806  			return false
   807  		}
   808  		return true
   809  	}
   810  	if idx == 0 {
   811  		return true
   812  	}
   813  	return a.baseObject.deleteStr(name, throw)
   814  }
   815  
   816  func (a *typedArrayObject) deleteIdx(idx valueInt, throw bool) bool {
   817  	if a.viewedArrayBuf.ensureNotDetached(false) && idx >= 0 && int64(idx) < int64(a.length) {
   818  		a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String())
   819  		return false
   820  	}
   821  
   822  	return true
   823  }
   824  
   825  func (a *typedArrayObject) stringKeys(all bool, accum []Value) []Value {
   826  	if accum == nil {
   827  		accum = make([]Value, 0, a.length)
   828  	}
   829  	for i := 0; i < a.length; i++ {
   830  		accum = append(accum, asciiString(strconv.Itoa(i)))
   831  	}
   832  	return a.baseObject.stringKeys(all, accum)
   833  }
   834  
   835  type typedArrayPropIter struct {
   836  	a   *typedArrayObject
   837  	idx int
   838  }
   839  
   840  func (i *typedArrayPropIter) next() (propIterItem, iterNextFunc) {
   841  	if i.idx < i.a.length {
   842  		name := strconv.Itoa(i.idx)
   843  		prop := i.a._getIdx(i.idx)
   844  		i.idx++
   845  		return propIterItem{name: asciiString(name), value: prop}, i.next
   846  	}
   847  
   848  	return i.a.baseObject.iterateStringKeys()()
   849  }
   850  
   851  func (a *typedArrayObject) iterateStringKeys() iterNextFunc {
   852  	return (&typedArrayPropIter{
   853  		a: a,
   854  	}).next
   855  }
   856  
   857  func (a *typedArrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
   858  	if typ == typeBytes {
   859  		dst.Set(reflect.ValueOf(a.viewedArrayBuf.data))
   860  		return nil
   861  	}
   862  	return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
   863  }
   864  
   865  func (a *typedArrayObject) export(_ *objectExportCtx) interface{} {
   866  	return a.typedArray.export(a.offset, a.length)
   867  }
   868  
   869  func (a *typedArrayObject) exportType() reflect.Type {
   870  	return a.typedArray.exportType()
   871  }
   872  
   873  func (o *dataViewObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
   874  	if typ == typeBytes {
   875  		dst.Set(reflect.ValueOf(o.viewedArrayBuf.data))
   876  		return nil
   877  	}
   878  	return o.baseObject.exportToArrayOrSlice(dst, typ, ctx)
   879  }
   880  
   881  func (r *Runtime) _newTypedArrayObject(buf *arrayBufferObject, offset, length, elemSize int, defCtor *Object, arr typedArray, proto *Object) *typedArrayObject {
   882  	o := &Object{runtime: r}
   883  	a := &typedArrayObject{
   884  		baseObject: baseObject{
   885  			val:        o,
   886  			class:      classObject,
   887  			prototype:  proto,
   888  			extensible: true,
   889  		},
   890  		viewedArrayBuf: buf,
   891  		offset:         offset,
   892  		length:         length,
   893  		elemSize:       elemSize,
   894  		defaultCtor:    defCtor,
   895  		typedArray:     arr,
   896  	}
   897  	o.self = a
   898  	a.init()
   899  	return a
   900  
   901  }
   902  
   903  func (r *Runtime) newUint8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   904  	return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8Array, (*uint8Array)(&buf.data), proto)
   905  }
   906  
   907  func (r *Runtime) newUint8ClampedArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   908  	return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8ClampedArray, (*uint8ClampedArray)(&buf.data), proto)
   909  }
   910  
   911  func (r *Runtime) newInt8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   912  	return r._newTypedArrayObject(buf, offset, length, 1, r.global.Int8Array, (*int8Array)(&buf.data), proto)
   913  }
   914  
   915  func (r *Runtime) newUint16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   916  	return r._newTypedArrayObject(buf, offset, length, 2, r.global.Uint16Array, (*uint16Array)(&buf.data), proto)
   917  }
   918  
   919  func (r *Runtime) newInt16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   920  	return r._newTypedArrayObject(buf, offset, length, 2, r.global.Int16Array, (*int16Array)(&buf.data), proto)
   921  }
   922  
   923  func (r *Runtime) newUint32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   924  	return r._newTypedArrayObject(buf, offset, length, 4, r.global.Uint32Array, (*uint32Array)(&buf.data), proto)
   925  }
   926  
   927  func (r *Runtime) newInt32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   928  	return r._newTypedArrayObject(buf, offset, length, 4, r.global.Int32Array, (*int32Array)(&buf.data), proto)
   929  }
   930  
   931  func (r *Runtime) newFloat32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   932  	return r._newTypedArrayObject(buf, offset, length, 4, r.global.Float32Array, (*float32Array)(&buf.data), proto)
   933  }
   934  
   935  func (r *Runtime) newFloat64ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
   936  	return r._newTypedArrayObject(buf, offset, length, 8, r.global.Float64Array, (*float64Array)(&buf.data), proto)
   937  }
   938  
   939  func (o *dataViewObject) getIdxAndByteOrder(getIdx int, littleEndianVal Value, size int) (int, byteOrder) {
   940  	o.viewedArrayBuf.ensureNotDetached(true)
   941  	if getIdx+size > o.byteLen {
   942  		panic(o.val.runtime.newError(o.val.runtime.global.RangeError, "Index %d is out of bounds", getIdx))
   943  	}
   944  	getIdx += o.byteOffset
   945  	var bo byteOrder
   946  	if littleEndianVal != nil {
   947  		if littleEndianVal.ToBoolean() {
   948  			bo = littleEndian
   949  		} else {
   950  			bo = bigEndian
   951  		}
   952  	} else {
   953  		bo = nativeEndian
   954  	}
   955  	return getIdx, bo
   956  }
   957  
   958  func (o *arrayBufferObject) ensureNotDetached(throw bool) bool {
   959  	if o.detached {
   960  		o.val.runtime.typeErrorResult(throw, "ArrayBuffer is detached")
   961  		return false
   962  	}
   963  	return true
   964  }
   965  
   966  func (o *arrayBufferObject) getFloat32(idx int, byteOrder byteOrder) float32 {
   967  	return math.Float32frombits(o.getUint32(idx, byteOrder))
   968  }
   969  
   970  func (o *arrayBufferObject) setFloat32(idx int, val float32, byteOrder byteOrder) {
   971  	o.setUint32(idx, math.Float32bits(val), byteOrder)
   972  }
   973  
   974  func (o *arrayBufferObject) getFloat64(idx int, byteOrder byteOrder) float64 {
   975  	return math.Float64frombits(o.getUint64(idx, byteOrder))
   976  }
   977  
   978  func (o *arrayBufferObject) setFloat64(idx int, val float64, byteOrder byteOrder) {
   979  	o.setUint64(idx, math.Float64bits(val), byteOrder)
   980  }
   981  
   982  func (o *arrayBufferObject) getUint64(idx int, byteOrder byteOrder) uint64 {
   983  	var b []byte
   984  	if byteOrder == nativeEndian {
   985  		b = o.data[idx : idx+8]
   986  	} else {
   987  		b = make([]byte, 8)
   988  		d := o.data[idx : idx+8]
   989  		b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] = d[7], d[6], d[5], d[4], d[3], d[2], d[1], d[0]
   990  	}
   991  	return *((*uint64)(unsafe.Pointer(&b[0])))
   992  }
   993  
   994  func (o *arrayBufferObject) setUint64(idx int, val uint64, byteOrder byteOrder) {
   995  	if byteOrder == nativeEndian {
   996  		*(*uint64)(unsafe.Pointer(&o.data[idx])) = val
   997  	} else {
   998  		b := (*[8]byte)(unsafe.Pointer(&val))
   999  		d := o.data[idx : idx+8]
  1000  		d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] = b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0]
  1001  	}
  1002  }
  1003  
  1004  func (o *arrayBufferObject) getUint32(idx int, byteOrder byteOrder) uint32 {
  1005  	var b []byte
  1006  	if byteOrder == nativeEndian {
  1007  		b = o.data[idx : idx+4]
  1008  	} else {
  1009  		b = make([]byte, 4)
  1010  		d := o.data[idx : idx+4]
  1011  		b[0], b[1], b[2], b[3] = d[3], d[2], d[1], d[0]
  1012  	}
  1013  	return *((*uint32)(unsafe.Pointer(&b[0])))
  1014  }
  1015  
  1016  func (o *arrayBufferObject) setUint32(idx int, val uint32, byteOrder byteOrder) {
  1017  	o.ensureNotDetached(true)
  1018  	if byteOrder == nativeEndian {
  1019  		*(*uint32)(unsafe.Pointer(&o.data[idx])) = val
  1020  	} else {
  1021  		b := (*[4]byte)(unsafe.Pointer(&val))
  1022  		d := o.data[idx : idx+4]
  1023  		d[0], d[1], d[2], d[3] = b[3], b[2], b[1], b[0]
  1024  	}
  1025  }
  1026  
  1027  func (o *arrayBufferObject) getUint16(idx int, byteOrder byteOrder) uint16 {
  1028  	var b []byte
  1029  	if byteOrder == nativeEndian {
  1030  		b = o.data[idx : idx+2]
  1031  	} else {
  1032  		b = make([]byte, 2)
  1033  		d := o.data[idx : idx+2]
  1034  		b[0], b[1] = d[1], d[0]
  1035  	}
  1036  	return *((*uint16)(unsafe.Pointer(&b[0])))
  1037  }
  1038  
  1039  func (o *arrayBufferObject) setUint16(idx int, val uint16, byteOrder byteOrder) {
  1040  	if byteOrder == nativeEndian {
  1041  		*(*uint16)(unsafe.Pointer(&o.data[idx])) = val
  1042  	} else {
  1043  		b := (*[2]byte)(unsafe.Pointer(&val))
  1044  		d := o.data[idx : idx+2]
  1045  		d[0], d[1] = b[1], b[0]
  1046  	}
  1047  }
  1048  
  1049  func (o *arrayBufferObject) getUint8(idx int) uint8 {
  1050  	return o.data[idx]
  1051  }
  1052  
  1053  func (o *arrayBufferObject) setUint8(idx int, val uint8) {
  1054  	o.data[idx] = val
  1055  }
  1056  
  1057  func (o *arrayBufferObject) getInt32(idx int, byteOrder byteOrder) int32 {
  1058  	return int32(o.getUint32(idx, byteOrder))
  1059  }
  1060  
  1061  func (o *arrayBufferObject) setInt32(idx int, val int32, byteOrder byteOrder) {
  1062  	o.setUint32(idx, uint32(val), byteOrder)
  1063  }
  1064  
  1065  func (o *arrayBufferObject) getInt16(idx int, byteOrder byteOrder) int16 {
  1066  	return int16(o.getUint16(idx, byteOrder))
  1067  }
  1068  
  1069  func (o *arrayBufferObject) setInt16(idx int, val int16, byteOrder byteOrder) {
  1070  	o.setUint16(idx, uint16(val), byteOrder)
  1071  }
  1072  
  1073  func (o *arrayBufferObject) getInt8(idx int) int8 {
  1074  	return int8(o.data[idx])
  1075  }
  1076  
  1077  func (o *arrayBufferObject) setInt8(idx int, val int8) {
  1078  	o.setUint8(idx, uint8(val))
  1079  }
  1080  
  1081  func (o *arrayBufferObject) detach() {
  1082  	o.data = nil
  1083  	o.detached = true
  1084  }
  1085  
  1086  func (o *arrayBufferObject) exportType() reflect.Type {
  1087  	return arrayBufferType
  1088  }
  1089  
  1090  func (o *arrayBufferObject) export(*objectExportCtx) interface{} {
  1091  	return ArrayBuffer{
  1092  		buf: o,
  1093  	}
  1094  }
  1095  
  1096  func (o *arrayBufferObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
  1097  	if typ == typeBytes {
  1098  		dst.Set(reflect.ValueOf(o.data))
  1099  		return nil
  1100  	}
  1101  	return o.baseObject.exportToArrayOrSlice(dst, typ, ctx)
  1102  }
  1103  
  1104  func (r *Runtime) _newArrayBuffer(proto *Object, o *Object) *arrayBufferObject {
  1105  	if o == nil {
  1106  		o = &Object{runtime: r}
  1107  	}
  1108  	b := &arrayBufferObject{
  1109  		baseObject: baseObject{
  1110  			class:      classObject,
  1111  			val:        o,
  1112  			prototype:  proto,
  1113  			extensible: true,
  1114  		},
  1115  	}
  1116  	o.self = b
  1117  	b.init()
  1118  	return b
  1119  }
  1120  
  1121  func init() {
  1122  	buf := [2]byte{}
  1123  	*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xCAFE)
  1124  
  1125  	switch buf {
  1126  	case [2]byte{0xFE, 0xCA}:
  1127  		nativeEndian = littleEndian
  1128  	case [2]byte{0xCA, 0xFE}:
  1129  		nativeEndian = bigEndian
  1130  	default:
  1131  		panic("Could not determine native endianness.")
  1132  	}
  1133  }