@@ -11,7 +11,7 @@ use crate::{
11
11
operations_on_objects:: {
12
12
construct, get, length_of_array_like, set, species_constructor,
13
13
} ,
14
- type_conversion:: { to_big_int, to_index, to_number} ,
14
+ type_conversion:: { IntegerOrInfinity , to_big_int, to_index, to_number, to_object } ,
15
15
} ,
16
16
builtins:: {
17
17
ArgumentsList , ArrayBuffer , BuiltinFunction ,
@@ -20,7 +20,10 @@ use crate::{
20
20
array_buffer_byte_length, clone_array_buffer, get_value_from_buffer,
21
21
is_detached_buffer, is_fixed_length_array_buffer, set_value_in_buffer,
22
22
} ,
23
- indexed_collections:: typed_array_objects:: typed_array_intrinsic_object:: require_internal_slot_typed_array,
23
+ indexed_collections:: typed_array_objects:: typed_array_intrinsic_object:: {
24
+ byte_slice_to_viewable, byte_slice_to_viewable_mut,
25
+ require_internal_slot_typed_array, split_typed_array_buffers,
26
+ } ,
24
27
ordinary:: get_prototype_from_constructor,
25
28
typed_array:: {
26
29
TypedArray ,
@@ -41,6 +44,8 @@ use crate::{
41
44
heap:: CreateHeapData ,
42
45
} ;
43
46
47
+ use super :: typed_array_intrinsic_object:: copy_between_different_type_typed_arrays;
48
+
44
49
/// Matches a TypedArray and defines a type T in the expression which
45
50
/// is the generic type of the viewable.
46
51
#[ macro_export]
@@ -1482,3 +1487,248 @@ pub(crate) fn typed_array_species_create_with_buffer<'a, T: Viewable>(
1482
1487
// 6. Return result.
1483
1488
Ok ( result. unbind ( ) )
1484
1489
}
1490
+
1491
+ /// [23.2.3.26.1 SetTypedArrayFromTypedArray ( target, targetOffset, source )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-settypedarrayfromtypedarray)
1492
+ /// The abstract operation SetTypedArrayFromTypedArray takes arguments target
1493
+ /// (a TypedArray), targetOffset (a non-negative integer or +∞), and source
1494
+ /// (a TypedArray) and returns either a normal completion containing unused
1495
+ /// or a throw completion. It sets multiple values in target, starting at index
1496
+ /// targetOffset, reading the values from source.
1497
+ pub ( crate ) fn set_typed_array_from_typed_array < ' a , TargetType : Viewable , SrcType : Viewable > (
1498
+ agent : & mut Agent ,
1499
+ target : TypedArray ,
1500
+ target_offset : IntegerOrInfinity ,
1501
+ source : TypedArray ,
1502
+ gc : NoGcScope < ' a , ' _ > ,
1503
+ ) -> JsResult < ' a , ( ) > {
1504
+ let target = target. bind ( gc) ;
1505
+ let source = source. bind ( gc) ;
1506
+ // 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
1507
+ let target_buffer = target. get_viewed_array_buffer ( agent, gc) ;
1508
+ // 2. Let targetRecord be MakeTypedArrayWithBufferWitnessRecord(target, seq-cst).
1509
+ let target_record =
1510
+ make_typed_array_with_buffer_witness_record ( agent, target, Ordering :: SeqCst , gc) ;
1511
+ // 3. If IsTypedArrayOutOfBounds(targetRecord) is true, throw a TypeError exception.
1512
+ if is_typed_array_out_of_bounds :: < TargetType > ( agent, & target_record, gc) {
1513
+ return Err ( agent. throw_exception_with_static_message (
1514
+ ExceptionType :: TypeError ,
1515
+ "TypedArray out of bounds" ,
1516
+ gc,
1517
+ ) ) ;
1518
+ } ;
1519
+ // 4. Let targetLength be TypedArrayLength(targetRecord).
1520
+ let target_length = typed_array_length :: < TargetType > ( agent, & target_record, gc) ;
1521
+ // 5. Let srcBuffer be source.[[ViewedArrayBuffer]].
1522
+ let mut src_buffer = source. get_viewed_array_buffer ( agent, gc) ;
1523
+ // 6. Let srcRecord be MakeTypedArrayWithBufferWitnessRecord(source, seq-cst).
1524
+ let src_record =
1525
+ make_typed_array_with_buffer_witness_record ( agent, source, Ordering :: SeqCst , gc) ;
1526
+ // 7. If IsTypedArrayOutOfBounds(srcRecord) is true, throw a TypeError exception.
1527
+ if is_typed_array_out_of_bounds :: < SrcType > ( agent, & src_record, gc) {
1528
+ return Err ( agent. throw_exception_with_static_message (
1529
+ ExceptionType :: TypeError ,
1530
+ "TypedArray out of bounds" ,
1531
+ gc,
1532
+ ) ) ;
1533
+ }
1534
+ // 8. Let srcLength be TypedArrayLength(srcRecord).
1535
+ let src_length = typed_array_length :: < SrcType > ( agent, & src_record, gc) ;
1536
+ // 9. Let targetType be TypedArrayElementType(target).
1537
+ // 10. Let targetElementSize be TypedArrayElementSize(target).
1538
+ let target_element_size = size_of :: < TargetType > ( ) ;
1539
+ // 11. Let targetByteOffset be target.[[ByteOffset]].
1540
+ let target_byte_offset = target. byte_offset ( agent) ;
1541
+ // 12. Let srcType be TypedArrayElementType(source).
1542
+ // 13. Let srcElementSize be TypedArrayElementSize(source).
1543
+ // 14. Let srcByteOffset be source.[[ByteOffset]].
1544
+ let src_byte_offset = source. byte_offset ( agent) ;
1545
+ // 15. If targetOffset = +∞, throw a RangeError exception.
1546
+ if target_offset. is_pos_infinity ( ) {
1547
+ return Err ( agent. throw_exception_with_static_message (
1548
+ ExceptionType :: RangeError ,
1549
+ "count must be less than infinity" ,
1550
+ gc,
1551
+ ) ) ;
1552
+ } ;
1553
+ // 16. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1554
+ let target_offset = target_offset. into_i64 ( ) as u64 ;
1555
+ if src_length as u64 + target_offset > target_length as u64 {
1556
+ return Err ( agent. throw_exception_with_static_message (
1557
+ ExceptionType :: RangeError ,
1558
+ "source length out of target bounds" ,
1559
+ gc,
1560
+ ) ) ;
1561
+ } ;
1562
+ let target_offset = target_offset as usize ;
1563
+ // 17. If target.[[ContentType]] is not source.[[ContentType]], throw a TypeError exception.
1564
+ let is_type_match = has_matching_content_type :: < TargetType > ( source) ;
1565
+ if !is_type_match {
1566
+ return Err ( agent. throw_exception_with_static_message (
1567
+ ExceptionType :: TypeError ,
1568
+ "TypedArray species did not match source" ,
1569
+ gc,
1570
+ ) ) ;
1571
+ } ;
1572
+ // 18. If IsSharedArrayBuffer(srcBuffer) is true,
1573
+ // IsSharedArrayBuffer(targetBuffer) is true, and
1574
+ // srcBuffer.[[ArrayBufferData]] is targetBuffer.[[ArrayBufferData]],
1575
+ // let sameSharedArrayBuffer be true; otherwise, let
1576
+ // sameSharedArrayBuffer be false.
1577
+ // 19. If SameValue(srcBuffer, targetBuffer) is true or
1578
+ // sameSharedArrayBuffer is true, then
1579
+ let src_byte_index = if src_buffer == target_buffer {
1580
+ // a. Let srcByteLength be TypedArrayByteLength(srcRecord).
1581
+ let src_byte_length = typed_array_byte_length :: < SrcType > ( agent, & src_record, gc) ;
1582
+ // b. Set srcBuffer to
1583
+ // ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcByteLength).
1584
+ src_buffer = clone_array_buffer ( agent, src_buffer, src_byte_offset, src_byte_length, gc)
1585
+ . unbind ( ) ?
1586
+ . bind ( gc) ;
1587
+ // c. Let srcByteIndex be 0.
1588
+ 0
1589
+ } else {
1590
+ src_byte_offset
1591
+ } ;
1592
+ debug_assert_ne ! ( src_buffer, target_buffer) ;
1593
+ debug_assert_ne ! (
1594
+ src_buffer. as_slice( agent) . as_ptr( ) ,
1595
+ target_buffer. as_slice( agent) . as_ptr( )
1596
+ ) ;
1597
+ // 21. Let targetByteIndex be (targetOffset × targetElementSize) + targetByteOffset.
1598
+ let target_byte_index = ( target_offset * target_element_size) + target_byte_offset;
1599
+ // 22. Let limit be targetByteIndex + (targetElementSize × srcLength).
1600
+ let limit = target_byte_index + ( target_element_size * src_length) ;
1601
+ // 23. If srcType is targetType, then
1602
+ if core:: any:: TypeId :: of :: < SrcType > ( ) == core:: any:: TypeId :: of :: < TargetType > ( ) {
1603
+ // a. NOTE: The transfer must be performed in a manner that preserves
1604
+ // the bit-level encoding of the source data.
1605
+ // Repeat, while targetByteIndex < limit,
1606
+ // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, uint8,
1607
+ // true, unordered).
1608
+ // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, uint8,
1609
+ // value, true, unordered).
1610
+ let ( target_slice, src_slice) = split_typed_array_buffers :: < SrcType > (
1611
+ agent,
1612
+ target_buffer,
1613
+ target_byte_index,
1614
+ src_buffer,
1615
+ src_byte_index,
1616
+ limit,
1617
+ ) ;
1618
+ target_slice. copy_from_slice ( src_slice) ;
1619
+ // iii. Set srcByteIndex to srcByteIndex + 1.
1620
+ // iv. Set targetByteIndex to targetByteIndex + 1.
1621
+ } else {
1622
+ // 24. Else,
1623
+ // a. Repeat, while targetByteIndex < limit,
1624
+ // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType, true, unordered).
1625
+ // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, unordered).
1626
+ let target_slice = byte_slice_to_viewable_mut :: < TargetType > (
1627
+ target_buffer. as_mut_slice ( agent) ,
1628
+ target_byte_index,
1629
+ limit,
1630
+ ) ;
1631
+ let target_ptr = target_slice. as_mut_ptr ( ) ;
1632
+ let target_len = target_slice. len ( ) ;
1633
+ let src_slice = byte_slice_to_viewable :: < SrcType > (
1634
+ src_buffer. as_slice ( agent) ,
1635
+ src_byte_index,
1636
+ // Note: source buffer is limited by the target buffer length.
1637
+ src_byte_index + target_len * core:: mem:: size_of :: < SrcType > ( ) ,
1638
+ ) ;
1639
+ // SAFETY: Confirmed beforehand that the two ArrayBuffers are in separate memory regions.
1640
+ let target_slice = unsafe { std:: slice:: from_raw_parts_mut ( target_ptr, target_len) } ;
1641
+ copy_between_different_type_typed_arrays :: < SrcType , TargetType > ( src_slice, target_slice) ;
1642
+ // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
1643
+ // iv. Set targetByteIndex to targetByteIndex + targetElementSize.
1644
+ }
1645
+ // 25. Return unused.
1646
+ Ok ( ( ) )
1647
+ }
1648
+
1649
+ /// ### [23.2.3.26.2 SetTypedArrayFromArrayLike ( target, targetOffset, source )](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-settypedarrayfromarraylike)
1650
+ /// The abstract operation SetTypedArrayFromArrayLike takes arguments target
1651
+ /// (a TypedArray), targetOffset (a non-negative integer or +∞), and source
1652
+ /// (an ECMAScript language value, but not a TypedArray) and returns either
1653
+ /// a normal completion containing unused or a throw completion. It sets
1654
+ /// multiple values in target, starting at index targetOffset, reading the
1655
+ /// values from source.
1656
+ pub ( crate ) fn set_typed_array_from_array_like < ' a , T : Viewable > (
1657
+ agent : & mut Agent ,
1658
+ target : Scoped < TypedArray > ,
1659
+ target_offset : IntegerOrInfinity ,
1660
+ source : Scoped < Value > ,
1661
+ mut gc : GcScope < ' a , ' _ > ,
1662
+ ) -> JsResult < ' a , ( ) > {
1663
+ // 1. Let targetRecord be MakeTypedArrayWithBufferWitnessRecord(target, seq-cst).
1664
+ let target_record = make_typed_array_with_buffer_witness_record (
1665
+ agent,
1666
+ target. get ( agent) ,
1667
+ Ordering :: SeqCst ,
1668
+ gc. nogc ( ) ,
1669
+ ) ;
1670
+ // 2. If IsTypedArrayOutOfBounds(targetRecord) is true, throw a TypeError exception.
1671
+ if is_typed_array_out_of_bounds :: < T > ( agent, & target_record, gc. nogc ( ) ) {
1672
+ return Err ( agent. throw_exception_with_static_message (
1673
+ ExceptionType :: TypeError ,
1674
+ "TypedArray out of bounds" ,
1675
+ gc. into_nogc ( ) ,
1676
+ ) ) ;
1677
+ } ;
1678
+ // 3. Let targetLength be TypedArrayLength(targetRecord).
1679
+ let target_length = typed_array_length :: < T > ( agent, & target_record, gc. nogc ( ) ) as u64 ;
1680
+ // 4. Let src be ? ToObject(source).
1681
+ let src = to_object ( agent, source. get ( agent) , gc. nogc ( ) )
1682
+ . unbind ( ) ?
1683
+ . bind ( gc. nogc ( ) ) ;
1684
+ // SAFETY: source is not shared.
1685
+ let source = unsafe { source. replace_self ( agent, src. unbind ( ) ) } ;
1686
+ // 5. Let srcLength be ? LengthOfArrayLike(src).
1687
+ let src_length = length_of_array_like ( agent, src. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ? as u64 ;
1688
+ let src = source;
1689
+ // 6. If targetOffset = +∞, throw a RangeError exception.
1690
+ if target_offset. is_pos_infinity ( ) {
1691
+ return Err ( agent. throw_exception_with_static_message (
1692
+ ExceptionType :: RangeError ,
1693
+ "count must be less than infinity" ,
1694
+ gc. into_nogc ( ) ,
1695
+ ) ) ;
1696
+ } ;
1697
+ let target_offset = target_offset. into_i64 ( ) as u64 ;
1698
+ // 7. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1699
+ if src_length + target_offset > target_length {
1700
+ return Err ( agent. throw_exception_with_static_message (
1701
+ ExceptionType :: RangeError ,
1702
+ "count must be less than infinity" ,
1703
+ gc. into_nogc ( ) ,
1704
+ ) ) ;
1705
+ } ;
1706
+ let target_offset = target_offset as usize ;
1707
+ let src_length = src_length as usize ;
1708
+ // 8. Let k be 0.
1709
+ let mut k = 0 ;
1710
+ // 9. Repeat, while k < srcLength,
1711
+ while k < src_length {
1712
+ // a. Let Pk be ! ToString(𝔽(k)).
1713
+ let pk = PropertyKey :: Integer ( k. try_into ( ) . unwrap ( ) ) ;
1714
+ // b. Let value be ? Get(src, Pk).
1715
+ let value = get ( agent, src. get ( agent) , pk, gc. reborrow ( ) )
1716
+ . unbind ( ) ?
1717
+ . bind ( gc. nogc ( ) ) ;
1718
+ // c. Let targetIndex be 𝔽(targetOffset + k).
1719
+ let target_index = target_offset + k;
1720
+ // d. Perform ? TypedArraySetElement(target, targetIndex, value).
1721
+ typed_array_set_element :: < T > (
1722
+ agent,
1723
+ target. get ( agent) ,
1724
+ target_index as i64 ,
1725
+ value. unbind ( ) ,
1726
+ gc. reborrow ( ) ,
1727
+ )
1728
+ . unbind ( ) ?;
1729
+ // e. Set k to k + 1.
1730
+ k += 1 ;
1731
+ }
1732
+ // 10. Return unused.
1733
+ Ok ( ( ) )
1734
+ }
0 commit comments