1package goja 2 3import ( 4 "math" 5 "reflect" 6 "strconv" 7 "unsafe" 8 9 "github.com/dop251/goja/unistring" 10) 11 12type byteOrder bool 13 14const ( 15 bigEndian byteOrder = false 16 littleEndian byteOrder = true 17) 18 19var ( 20 nativeEndian byteOrder 21 22 arrayBufferType = reflect.TypeOf(ArrayBuffer{}) 23) 24 25type typedArrayObjectCtor func(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject 26 27type 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. 36type ArrayBuffer struct { 37 buf *arrayBufferObject 38} 39 40type dataViewObject struct { 41 baseObject 42 viewedArrayBuf *arrayBufferObject 43 byteLen, byteOffset int 44} 45 46type 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} 56 57type uint8Array []uint8 58type uint8ClampedArray []uint8 59type int8Array []int8 60type uint16Array []uint16 61type int16Array []int16 62type uint32Array []uint32 63type int32Array []int32 64type float32Array []float32 65type float64Array []float64 66 67type typedArrayObject struct { 68 baseObject 69 viewedArrayBuf *arrayBufferObject 70 defaultCtor *Object 71 length, offset int 72 elemSize int 73 typedArray typedArray 74} 75 76func (a ArrayBuffer) toValue(r *Runtime) Value { 77 if a.buf == nil { 78 return _null 79 } 80 v := a.buf.val 81 if v.runtime != r { 82 panic(r.NewTypeError("Illegal runtime transition of an ArrayBuffer")) 83 } 84 return v 85} 86 87// Bytes returns the underlying []byte for this ArrayBuffer. 88// For detached ArrayBuffers returns nil. 89func (a ArrayBuffer) Bytes() []byte { 90 return a.buf.data 91} 92 93// Detach the ArrayBuffer. After this, the underlying []byte becomes unreferenced and any attempt 94// to use this ArrayBuffer results in a TypeError. 95// Returns false if it was already detached, true otherwise. 96// Note, this method may only be called from the goroutine that 'owns' the Runtime, it may not 97// be called concurrently. 98func (a ArrayBuffer) Detach() bool { 99 if a.buf.detached { 100 return false 101 } 102 a.buf.detach() 103 return true 104} 105 106// Detached returns true if the ArrayBuffer is detached. 107func (a ArrayBuffer) Detached() bool { 108 return a.buf.detached 109} 110 111func (r *Runtime) NewArrayBuffer(data []byte) ArrayBuffer { 112 buf := r._newArrayBuffer(r.global.ArrayBufferPrototype, nil) 113 buf.data = data 114 return ArrayBuffer{ 115 buf: buf, 116 } 117} 118 119func (a *uint8Array) get(idx int) Value { 120 return intToValue(int64((*a)[idx])) 121} 122 123func (a *uint8Array) getRaw(idx int) uint64 { 124 return uint64((*a)[idx]) 125} 126 127func (a *uint8Array) set(idx int, value Value) { 128 (*a)[idx] = toUint8(value) 129} 130 131func (a *uint8Array) toRaw(v Value) uint64 { 132 return uint64(toUint8(v)) 133} 134 135func (a *uint8Array) setRaw(idx int, v uint64) { 136 (*a)[idx] = uint8(v) 137} 138 139func (a *uint8Array) less(i, j int) bool { 140 return (*a)[i] < (*a)[j] 141} 142 143func (a *uint8Array) swap(i, j int) { 144 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 145} 146 147func (a *uint8Array) typeMatch(v Value) bool { 148 if i, ok := v.(valueInt); ok { 149 return i >= 0 && i <= 255 150 } 151 return false 152} 153 154func (a *uint8ClampedArray) get(idx int) Value { 155 return intToValue(int64((*a)[idx])) 156} 157 158func (a *uint8ClampedArray) getRaw(idx int) uint64 { 159 return uint64((*a)[idx]) 160} 161 162func (a *uint8ClampedArray) set(idx int, value Value) { 163 (*a)[idx] = toUint8Clamp(value) 164} 165 166func (a *uint8ClampedArray) toRaw(v Value) uint64 { 167 return uint64(toUint8Clamp(v)) 168} 169 170func (a *uint8ClampedArray) setRaw(idx int, v uint64) { 171 (*a)[idx] = uint8(v) 172} 173 174func (a *uint8ClampedArray) less(i, j int) bool { 175 return (*a)[i] < (*a)[j] 176} 177 178func (a *uint8ClampedArray) swap(i, j int) { 179 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 180} 181 182func (a *uint8ClampedArray) typeMatch(v Value) bool { 183 if i, ok := v.(valueInt); ok { 184 return i >= 0 && i <= 255 185 } 186 return false 187} 188 189func (a *int8Array) get(idx int) Value { 190 return intToValue(int64((*a)[idx])) 191} 192 193func (a *int8Array) getRaw(idx int) uint64 { 194 return uint64((*a)[idx]) 195} 196 197func (a *int8Array) set(idx int, value Value) { 198 (*a)[idx] = toInt8(value) 199} 200 201func (a *int8Array) toRaw(v Value) uint64 { 202 return uint64(toInt8(v)) 203} 204 205func (a *int8Array) setRaw(idx int, v uint64) { 206 (*a)[idx] = int8(v) 207} 208 209func (a *int8Array) less(i, j int) bool { 210 return (*a)[i] < (*a)[j] 211} 212 213func (a *int8Array) swap(i, j int) { 214 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 215} 216 217func (a *int8Array) typeMatch(v Value) bool { 218 if i, ok := v.(valueInt); ok { 219 return i >= math.MinInt8 && i <= math.MaxInt8 220 } 221 return false 222} 223 224func (a *uint16Array) get(idx int) Value { 225 return intToValue(int64((*a)[idx])) 226} 227 228func (a *uint16Array) getRaw(idx int) uint64 { 229 return uint64((*a)[idx]) 230} 231 232func (a *uint16Array) set(idx int, value Value) { 233 (*a)[idx] = toUint16(value) 234} 235 236func (a *uint16Array) toRaw(v Value) uint64 { 237 return uint64(toUint16(v)) 238} 239 240func (a *uint16Array) setRaw(idx int, v uint64) { 241 (*a)[idx] = uint16(v) 242} 243 244func (a *uint16Array) less(i, j int) bool { 245 return (*a)[i] < (*a)[j] 246} 247 248func (a *uint16Array) swap(i, j int) { 249 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 250} 251 252func (a *uint16Array) typeMatch(v Value) bool { 253 if i, ok := v.(valueInt); ok { 254 return i >= 0 && i <= math.MaxUint16 255 } 256 return false 257} 258 259func (a *int16Array) get(idx int) Value { 260 return intToValue(int64((*a)[idx])) 261} 262 263func (a *int16Array) getRaw(idx int) uint64 { 264 return uint64((*a)[idx]) 265} 266 267func (a *int16Array) set(idx int, value Value) { 268 (*a)[idx] = toInt16(value) 269} 270 271func (a *int16Array) toRaw(v Value) uint64 { 272 return uint64(toInt16(v)) 273} 274 275func (a *int16Array) setRaw(idx int, v uint64) { 276 (*a)[idx] = int16(v) 277} 278 279func (a *int16Array) less(i, j int) bool { 280 return (*a)[i] < (*a)[j] 281} 282 283func (a *int16Array) swap(i, j int) { 284 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 285} 286 287func (a *int16Array) typeMatch(v Value) bool { 288 if i, ok := v.(valueInt); ok { 289 return i >= math.MinInt16 && i <= math.MaxInt16 290 } 291 return false 292} 293 294func (a *uint32Array) get(idx int) Value { 295 return intToValue(int64((*a)[idx])) 296} 297 298func (a *uint32Array) getRaw(idx int) uint64 { 299 return uint64((*a)[idx]) 300} 301 302func (a *uint32Array) set(idx int, value Value) { 303 (*a)[idx] = toUint32(value) 304} 305 306func (a *uint32Array) toRaw(v Value) uint64 { 307 return uint64(toUint32(v)) 308} 309 310func (a *uint32Array) setRaw(idx int, v uint64) { 311 (*a)[idx] = uint32(v) 312} 313 314func (a *uint32Array) less(i, j int) bool { 315 return (*a)[i] < (*a)[j] 316} 317 318func (a *uint32Array) swap(i, j int) { 319 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 320} 321 322func (a *uint32Array) typeMatch(v Value) bool { 323 if i, ok := v.(valueInt); ok { 324 return i >= 0 && i <= math.MaxUint32 325 } 326 return false 327} 328 329func (a *int32Array) get(idx int) Value { 330 return intToValue(int64((*a)[idx])) 331} 332 333func (a *int32Array) getRaw(idx int) uint64 { 334 return uint64((*a)[idx]) 335} 336 337func (a *int32Array) set(idx int, value Value) { 338 (*a)[idx] = toInt32(value) 339} 340 341func (a *int32Array) toRaw(v Value) uint64 { 342 return uint64(toInt32(v)) 343} 344 345func (a *int32Array) setRaw(idx int, v uint64) { 346 (*a)[idx] = int32(v) 347} 348 349func (a *int32Array) less(i, j int) bool { 350 return (*a)[i] < (*a)[j] 351} 352 353func (a *int32Array) swap(i, j int) { 354 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 355} 356 357func (a *int32Array) typeMatch(v Value) bool { 358 if i, ok := v.(valueInt); ok { 359 return i >= math.MinInt32 && i <= math.MaxInt32 360 } 361 return false 362} 363 364func (a *float32Array) get(idx int) Value { 365 return floatToValue(float64((*a)[idx])) 366} 367 368func (a *float32Array) getRaw(idx int) uint64 { 369 return uint64(math.Float32bits((*a)[idx])) 370} 371 372func (a *float32Array) set(idx int, value Value) { 373 (*a)[idx] = toFloat32(value) 374} 375 376func (a *float32Array) toRaw(v Value) uint64 { 377 return uint64(math.Float32bits(toFloat32(v))) 378} 379 380func (a *float32Array) setRaw(idx int, v uint64) { 381 (*a)[idx] = math.Float32frombits(uint32(v)) 382} 383 384func typedFloatLess(x, y float64) bool { 385 xNan := math.IsNaN(x) 386 yNan := math.IsNaN(y) 387 if yNan { 388 return !xNan 389 } else if xNan { 390 return false 391 } 392 if x == 0 && y == 0 { // handle neg zero 393 return math.Signbit(x) 394 } 395 return x < y 396} 397 398func (a *float32Array) less(i, j int) bool { 399 return typedFloatLess(float64((*a)[i]), float64((*a)[j])) 400} 401 402func (a *float32Array) swap(i, j int) { 403 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 404} 405 406func (a *float32Array) typeMatch(v Value) bool { 407 switch v.(type) { 408 case valueInt, valueFloat: 409 return true 410 } 411 return false 412} 413 414func (a *float64Array) get(idx int) Value { 415 return floatToValue((*a)[idx]) 416} 417 418func (a *float64Array) getRaw(idx int) uint64 { 419 return math.Float64bits((*a)[idx]) 420} 421 422func (a *float64Array) set(idx int, value Value) { 423 (*a)[idx] = value.ToFloat() 424} 425 426func (a *float64Array) toRaw(v Value) uint64 { 427 return math.Float64bits(v.ToFloat()) 428} 429 430func (a *float64Array) setRaw(idx int, v uint64) { 431 (*a)[idx] = math.Float64frombits(v) 432} 433 434func (a *float64Array) less(i, j int) bool { 435 return typedFloatLess((*a)[i], (*a)[j]) 436} 437 438func (a *float64Array) swap(i, j int) { 439 (*a)[i], (*a)[j] = (*a)[j], (*a)[i] 440} 441 442func (a *float64Array) typeMatch(v Value) bool { 443 switch v.(type) { 444 case valueInt, valueFloat: 445 return true 446 } 447 return false 448} 449 450func (a *typedArrayObject) _getIdx(idx int) Value { 451 if 0 <= idx && idx < a.length { 452 if !a.viewedArrayBuf.ensureNotDetached(false) { 453 return nil 454 } 455 return a.typedArray.get(idx + a.offset) 456 } 457 return nil 458} 459 460func (a *typedArrayObject) getOwnPropStr(name unistring.String) Value { 461 idx, ok := strToIntNum(name) 462 if ok { 463 v := a._getIdx(idx) 464 if v != nil { 465 return &valueProperty{ 466 value: v, 467 writable: true, 468 enumerable: true, 469 configurable: true, 470 } 471 } 472 return nil 473 } 474 if idx == 0 { 475 return nil 476 } 477 return a.baseObject.getOwnPropStr(name) 478} 479 480func (a *typedArrayObject) getOwnPropIdx(idx valueInt) Value { 481 v := a._getIdx(toIntClamp(int64(idx))) 482 if v != nil { 483 return &valueProperty{ 484 value: v, 485 writable: true, 486 enumerable: true, 487 configurable: true, 488 } 489 } 490 return nil 491} 492 493func (a *typedArrayObject) getStr(name unistring.String, receiver Value) Value { 494 idx, ok := strToIntNum(name) 495 if ok { 496 return a._getIdx(idx) 497 } 498 if idx == 0 { 499 return nil 500 } 501 return a.baseObject.getStr(name, receiver) 502} 503 504func (a *typedArrayObject) getIdx(idx valueInt, receiver Value) Value { 505 return a._getIdx(toIntClamp(int64(idx))) 506} 507 508func (a *typedArrayObject) isValidIntegerIndex(idx int, throw bool) bool { 509 if a.viewedArrayBuf.ensureNotDetached(throw) { 510 if idx >= 0 && idx < a.length { 511 return true 512 } 513 a.val.runtime.typeErrorResult(throw, "Invalid typed array index") 514 } 515 return false 516} 517 518func (a *typedArrayObject) _putIdx(idx int, v Value) { 519 v = v.ToNumber() 520 if a.isValidIntegerIndex(idx, false) { 521 a.typedArray.set(idx+a.offset, v) 522 } 523} 524 525func (a *typedArrayObject) _hasIdx(idx int) bool { 526 return a.isValidIntegerIndex(idx, false) 527} 528 529func (a *typedArrayObject) setOwnStr(p unistring.String, v Value, throw bool) bool { 530 idx, ok := strToIntNum(p) 531 if ok { 532 a._putIdx(idx, v) 533 return true 534 } 535 if idx == 0 { 536 v.ToNumber() // make sure it throws 537 return false 538 } 539 return a.baseObject.setOwnStr(p, v, throw) 540} 541 542func (a *typedArrayObject) setOwnIdx(p valueInt, v Value, throw bool) bool { 543 a._putIdx(toIntClamp(int64(p)), v) 544 return true 545} 546 547func (a *typedArrayObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) { 548 return a._setForeignStr(p, a.getOwnPropStr(p), v, receiver, throw) 549} 550 551func (a *typedArrayObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) { 552 return a._setForeignIdx(p, trueValIfPresent(a.hasOwnPropertyIdx(p)), v, receiver, throw) 553} 554 555func (a *typedArrayObject) hasOwnPropertyStr(name unistring.String) bool { 556 idx, ok := strToIntNum(name) 557 if ok { 558 return a._hasIdx(idx) 559 } 560 if idx == 0 { 561 return false 562 } 563 return a.baseObject.hasOwnPropertyStr(name) 564} 565 566func (a *typedArrayObject) hasOwnPropertyIdx(idx valueInt) bool { 567 return a._hasIdx(toIntClamp(int64(idx))) 568} 569 570func (a *typedArrayObject) _defineIdxProperty(idx int, desc PropertyDescriptor, throw bool) bool { 571 if desc.Configurable == FLAG_FALSE || desc.Enumerable == FLAG_FALSE || desc.IsAccessor() || desc.Writable == FLAG_FALSE { 572 a.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", idx) 573 return false 574 } 575 _, ok := a._defineOwnProperty(unistring.String(strconv.Itoa(idx)), a.getOwnPropIdx(valueInt(idx)), desc, throw) 576 if ok { 577 if !a.isValidIntegerIndex(idx, throw) { 578 return false 579 } 580 a._putIdx(idx, desc.Value) 581 return true 582 } 583 return ok 584} 585 586func (a *typedArrayObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool { 587 idx, ok := strToIntNum(name) 588 if ok { 589 return a._defineIdxProperty(idx, desc, throw) 590 } 591 if idx == 0 { 592 a.viewedArrayBuf.ensureNotDetached(throw) 593 a.val.runtime.typeErrorResult(throw, "Invalid typed array index") 594 return false 595 } 596 return a.baseObject.defineOwnPropertyStr(name, desc, throw) 597} 598 599func (a *typedArrayObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool { 600 return a._defineIdxProperty(toIntClamp(int64(name)), desc, throw) 601} 602 603func (a *typedArrayObject) deleteStr(name unistring.String, throw bool) bool { 604 idx, ok := strToIntNum(name) 605 if ok { 606 if !a.isValidIntegerIndex(idx, false) { 607 a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String()) 608 return false 609 } 610 return true 611 } 612 if idx == 0 { 613 return true 614 } 615 return a.baseObject.deleteStr(name, throw) 616} 617 618func (a *typedArrayObject) deleteIdx(idx valueInt, throw bool) bool { 619 if a.viewedArrayBuf.ensureNotDetached(throw) && idx >= 0 && int64(idx) < int64(a.length) { 620 a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String()) 621 return false 622 } 623 624 return true 625} 626 627func (a *typedArrayObject) ownKeys(all bool, accum []Value) []Value { 628 if accum == nil { 629 accum = make([]Value, 0, a.length) 630 } 631 for i := 0; i < a.length; i++ { 632 accum = append(accum, asciiString(strconv.Itoa(i))) 633 } 634 return a.baseObject.ownKeys(all, accum) 635} 636 637type typedArrayPropIter struct { 638 a *typedArrayObject 639 idx int 640} 641 642func (i *typedArrayPropIter) next() (propIterItem, iterNextFunc) { 643 if i.idx < i.a.length { 644 name := strconv.Itoa(i.idx) 645 prop := i.a._getIdx(i.idx) 646 i.idx++ 647 return propIterItem{name: unistring.String(name), value: prop}, i.next 648 } 649 650 return i.a.baseObject.enumerateOwnKeys()() 651} 652 653func (a *typedArrayObject) enumerateOwnKeys() iterNextFunc { 654 return (&typedArrayPropIter{ 655 a: a, 656 }).next 657} 658 659func (r *Runtime) _newTypedArrayObject(buf *arrayBufferObject, offset, length, elemSize int, defCtor *Object, arr typedArray, proto *Object) *typedArrayObject { 660 o := &Object{runtime: r} 661 a := &typedArrayObject{ 662 baseObject: baseObject{ 663 val: o, 664 class: classObject, 665 prototype: proto, 666 extensible: true, 667 }, 668 viewedArrayBuf: buf, 669 offset: offset, 670 length: length, 671 elemSize: elemSize, 672 defaultCtor: defCtor, 673 typedArray: arr, 674 } 675 o.self = a 676 a.init() 677 return a 678 679} 680 681func (r *Runtime) newUint8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 682 return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8Array, (*uint8Array)(&buf.data), proto) 683} 684 685func (r *Runtime) newUint8ClampedArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 686 return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8ClampedArray, (*uint8ClampedArray)(&buf.data), proto) 687} 688 689func (r *Runtime) newInt8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 690 return r._newTypedArrayObject(buf, offset, length, 1, r.global.Int8Array, (*int8Array)(unsafe.Pointer(&buf.data)), proto) 691} 692 693func (r *Runtime) newUint16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 694 return r._newTypedArrayObject(buf, offset, length, 2, r.global.Uint16Array, (*uint16Array)(unsafe.Pointer(&buf.data)), proto) 695} 696 697func (r *Runtime) newInt16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 698 return r._newTypedArrayObject(buf, offset, length, 2, r.global.Int16Array, (*int16Array)(unsafe.Pointer(&buf.data)), proto) 699} 700 701func (r *Runtime) newUint32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 702 return r._newTypedArrayObject(buf, offset, length, 4, r.global.Uint32Array, (*uint32Array)(unsafe.Pointer(&buf.data)), proto) 703} 704 705func (r *Runtime) newInt32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 706 return r._newTypedArrayObject(buf, offset, length, 4, r.global.Int32Array, (*int32Array)(unsafe.Pointer(&buf.data)), proto) 707} 708 709func (r *Runtime) newFloat32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 710 return r._newTypedArrayObject(buf, offset, length, 4, r.global.Float32Array, (*float32Array)(unsafe.Pointer(&buf.data)), proto) 711} 712 713func (r *Runtime) newFloat64ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject { 714 return r._newTypedArrayObject(buf, offset, length, 8, r.global.Float64Array, (*float64Array)(unsafe.Pointer(&buf.data)), proto) 715} 716 717func (o *dataViewObject) getIdxAndByteOrder(idxVal, littleEndianVal Value, size int) (int, byteOrder) { 718 getIdx := o.val.runtime.toIndex(idxVal) 719 o.viewedArrayBuf.ensureNotDetached(true) 720 if getIdx+size > o.byteLen { 721 panic(o.val.runtime.newError(o.val.runtime.global.RangeError, "Index %d is out of bounds", getIdx)) 722 } 723 getIdx += o.byteOffset 724 var bo byteOrder 725 if littleEndianVal != nil { 726 if littleEndianVal.ToBoolean() { 727 bo = littleEndian 728 } else { 729 bo = bigEndian 730 } 731 } else { 732 bo = nativeEndian 733 } 734 return getIdx, bo 735} 736 737func (o *arrayBufferObject) ensureNotDetached(throw bool) bool { 738 if o.detached { 739 o.val.runtime.typeErrorResult(throw, "ArrayBuffer is detached") 740 return false 741 } 742 return true 743} 744 745func (o *arrayBufferObject) getFloat32(idx int, byteOrder byteOrder) float32 { 746 return math.Float32frombits(o.getUint32(idx, byteOrder)) 747} 748 749func (o *arrayBufferObject) setFloat32(idx int, val float32, byteOrder byteOrder) { 750 o.setUint32(idx, math.Float32bits(val), byteOrder) 751} 752 753func (o *arrayBufferObject) getFloat64(idx int, byteOrder byteOrder) float64 { 754 return math.Float64frombits(o.getUint64(idx, byteOrder)) 755} 756 757func (o *arrayBufferObject) setFloat64(idx int, val float64, byteOrder byteOrder) { 758 o.setUint64(idx, math.Float64bits(val), byteOrder) 759} 760 761func (o *arrayBufferObject) getUint64(idx int, byteOrder byteOrder) uint64 { 762 var b []byte 763 if byteOrder == nativeEndian { 764 b = o.data[idx : idx+8] 765 } else { 766 b = make([]byte, 8) 767 d := o.data[idx : idx+8] 768 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] 769 } 770 return *((*uint64)(unsafe.Pointer(&b[0]))) 771} 772 773func (o *arrayBufferObject) setUint64(idx int, val uint64, byteOrder byteOrder) { 774 if byteOrder == nativeEndian { 775 *(*uint64)(unsafe.Pointer(&o.data[idx])) = val 776 } else { 777 b := (*[8]byte)(unsafe.Pointer(&val)) 778 d := o.data[idx : idx+8] 779 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] 780 } 781} 782 783func (o *arrayBufferObject) getUint32(idx int, byteOrder byteOrder) uint32 { 784 var b []byte 785 if byteOrder == nativeEndian { 786 b = o.data[idx : idx+4] 787 } else { 788 b = make([]byte, 4) 789 d := o.data[idx : idx+4] 790 b[0], b[1], b[2], b[3] = d[3], d[2], d[1], d[0] 791 } 792 return *((*uint32)(unsafe.Pointer(&b[0]))) 793} 794 795func (o *arrayBufferObject) setUint32(idx int, val uint32, byteOrder byteOrder) { 796 if byteOrder == nativeEndian { 797 *(*uint32)(unsafe.Pointer(&o.data[idx])) = val 798 } else { 799 b := (*[4]byte)(unsafe.Pointer(&val)) 800 d := o.data[idx : idx+4] 801 d[0], d[1], d[2], d[3] = b[3], b[2], b[1], b[0] 802 } 803} 804 805func (o *arrayBufferObject) getUint16(idx int, byteOrder byteOrder) uint16 { 806 var b []byte 807 if byteOrder == nativeEndian { 808 b = o.data[idx : idx+2] 809 } else { 810 b = make([]byte, 2) 811 d := o.data[idx : idx+2] 812 b[0], b[1] = d[1], d[0] 813 } 814 return *((*uint16)(unsafe.Pointer(&b[0]))) 815} 816 817func (o *arrayBufferObject) setUint16(idx int, val uint16, byteOrder byteOrder) { 818 if byteOrder == nativeEndian { 819 *(*uint16)(unsafe.Pointer(&o.data[idx])) = val 820 } else { 821 b := (*[2]byte)(unsafe.Pointer(&val)) 822 d := o.data[idx : idx+2] 823 d[0], d[1] = b[1], b[0] 824 } 825} 826 827func (o *arrayBufferObject) getUint8(idx int) uint8 { 828 return o.data[idx] 829} 830 831func (o *arrayBufferObject) setUint8(idx int, val uint8) { 832 o.data[idx] = val 833} 834 835func (o *arrayBufferObject) getInt32(idx int, byteOrder byteOrder) int32 { 836 return int32(o.getUint32(idx, byteOrder)) 837} 838 839func (o *arrayBufferObject) setInt32(idx int, val int32, byteOrder byteOrder) { 840 o.setUint32(idx, uint32(val), byteOrder) 841} 842 843func (o *arrayBufferObject) getInt16(idx int, byteOrder byteOrder) int16 { 844 return int16(o.getUint16(idx, byteOrder)) 845} 846 847func (o *arrayBufferObject) setInt16(idx int, val int16, byteOrder byteOrder) { 848 o.setUint16(idx, uint16(val), byteOrder) 849} 850 851func (o *arrayBufferObject) getInt8(idx int) int8 { 852 return int8(o.data[idx]) 853} 854 855func (o *arrayBufferObject) setInt8(idx int, val int8) { 856 o.setUint8(idx, uint8(val)) 857} 858 859func (o *arrayBufferObject) detach() { 860 o.data = nil 861 o.detached = true 862} 863 864func (o *arrayBufferObject) exportType() reflect.Type { 865 return arrayBufferType 866} 867 868func (o *arrayBufferObject) export(*objectExportCtx) interface{} { 869 return ArrayBuffer{ 870 buf: o, 871 } 872} 873 874func (r *Runtime) _newArrayBuffer(proto *Object, o *Object) *arrayBufferObject { 875 if o == nil { 876 o = &Object{runtime: r} 877 } 878 b := &arrayBufferObject{ 879 baseObject: baseObject{ 880 class: classObject, 881 val: o, 882 prototype: proto, 883 extensible: true, 884 }, 885 } 886 o.self = b 887 b.init() 888 return b 889} 890 891func init() { 892 buf := [2]byte{} 893 *(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xCAFE) 894 895 switch buf { 896 case [2]byte{0xFE, 0xCA}: 897 nativeEndian = littleEndian 898 case [2]byte{0xCA, 0xFE}: 899 nativeEndian = bigEndian 900 default: 901 panic("Could not determine native endianness.") 902 } 903} 904