@@ -1649,195 +1649,207 @@ in
1649
1649
do
1650
1650
{
1651
1651
import core.stdc.string ;
1652
-
1653
- void * newdata;
1654
- auto tinext = unqualify(ti.next);
1655
- auto sizeelem = tinext.tsize;
1656
- auto initializer = tinext.initializer();
1657
- auto initsize = initializer.length;
1658
-
1659
- assert (sizeelem);
1660
- assert (initsize);
1661
- assert (initsize <= sizeelem);
1662
- assert ((sizeelem / initsize) * initsize == sizeelem);
1652
+ import core.exception : onOutOfMemoryError;
1663
1653
1664
1654
debug (PRINTF )
1665
1655
{
1666
- printf(" _d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d )\n " , p, sizeelem, newlength, initsize );
1656
+ // printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
1667
1657
if (p)
1668
- printf(" \t p.data = %p, p.length = %d\n " , (* p).ptr, (* p).length);
1658
+ printf(" \t p.ptr = %p, p.length = %d\n " , (* p).ptr, (* p).length);
1669
1659
}
1670
1660
1671
- if (newlength)
1661
+ if (newlength <= ( * p).length )
1672
1662
{
1673
- version (D_InlineAsm_X86 )
1674
- {
1675
- size_t newsize = void ;
1663
+ * p = (* p)[0 .. newlength];
1664
+ void * newdata = (* p).ptr;
1665
+ return newdata[0 .. newlength];
1666
+ }
1667
+ auto tinext = unqualify(ti.next);
1668
+ size_t sizeelem = tinext.tsize;
1676
1669
1677
- asm
1678
- {
1679
- mov EAX ,newlength ;
1680
- mul EAX ,sizeelem ;
1681
- mov newsize,EAX ;
1682
- jc Loverflow ;
1683
- }
1670
+ /* Calculate: newsize = newlength * sizeelem
1671
+ */
1672
+ bool overflow = false ;
1673
+ version (D_InlineAsm_X86 )
1674
+ {
1675
+ size_t newsize = void ;
1676
+
1677
+ asm pure nothrow @nogc
1678
+ {
1679
+ mov EAX , newlength;
1680
+ mul EAX , sizeelem;
1681
+ mov newsize, EAX ;
1682
+ setc overflow;
1684
1683
}
1685
- else version (D_InlineAsm_X86_64 )
1684
+ }
1685
+ else version (D_InlineAsm_X86_64 )
1686
+ {
1687
+ size_t newsize = void ;
1688
+
1689
+ asm pure nothrow @nogc
1686
1690
{
1687
- size_t newsize = void ;
1691
+ mov RAX , newlength;
1692
+ mul RAX , sizeelem;
1693
+ mov newsize, RAX ;
1694
+ setc overflow;
1695
+ }
1696
+ }
1697
+ else
1698
+ {
1699
+ import core.checkedint : mulu;
1700
+ const size_t newsize = mulu(sizeelem, newlength, overflow);
1701
+ }
1702
+ if (overflow)
1703
+ {
1704
+ onOutOfMemoryError();
1705
+ assert (0 );
1706
+ }
1688
1707
1689
- asm
1690
- {
1691
- mov RAX ,newlength ;
1692
- mul RAX ,sizeelem ;
1693
- mov newsize,RAX ;
1694
- jc Loverflow ;
1695
- }
1708
+ debug (PRINTF ) printf(" newsize = %x, newlength = %x\n " , newsize, newlength);
1709
+
1710
+ const isshared = typeid (ti) is typeid (TypeInfo_Shared);
1711
+
1712
+ static void doInitialize (void * start, void * end, const void [] initializer)
1713
+ {
1714
+ if (initializer.length == 1 )
1715
+ {
1716
+ memset(start, * (cast (ubyte * )initializer.ptr), end - start);
1696
1717
}
1697
1718
else
1698
1719
{
1699
- import core.checkedint : mulu;
1720
+ auto q = initializer.ptr;
1721
+ immutable initsize = initializer.length;
1722
+ for (; start < end; start += initsize)
1723
+ {
1724
+ memcpy(start, q, initsize);
1725
+ }
1726
+ }
1727
+ }
1700
1728
1701
- bool overflow = false ;
1702
- size_t newsize = mulu(sizeelem, newlength, overflow);
1703
- if (overflow)
1704
- goto Loverflow;
1729
+ if (! (* p).ptr)
1730
+ {
1731
+ // pointer was null, need to allocate
1732
+ auto info = __arrayAlloc(newsize, ti, tinext);
1733
+ if (info.base is null )
1734
+ {
1735
+ onOutOfMemoryError();
1736
+ assert (0 );
1705
1737
}
1706
- debug (PRINTF ) printf(" newsize = %x, newlength = %x\n " , newsize, newlength);
1738
+ __setArrayAllocLength(info, newsize, isshared, tinext);
1739
+ if (! isshared)
1740
+ __insertBlkInfoCache(info, null );
1741
+ void * newdata = cast (byte * )__arrayStart(info);
1742
+ doInitialize(newdata, newdata + newsize, tinext.initializer);
1743
+ * p = newdata[0 .. newlength];
1744
+ return * p;
1745
+ }
1707
1746
1747
+ const size_t size = (* p).length * sizeelem;
1748
+ auto bic = isshared ? null : __getBlkInfo((* p).ptr);
1749
+ auto info = bic ? * bic : GC .query((* p).ptr);
1708
1750
1709
- size_t size = (* p).length * sizeelem;
1710
- auto isshared = typeid (ti) is typeid (TypeInfo_Shared);
1711
- if ((* p).ptr)
1751
+ /* Attempt to extend past the end of the existing array.
1752
+ * If not possible, allocate new space for entire array and copy.
1753
+ */
1754
+ bool allocateAndCopy = false ;
1755
+ void * newdata = (* p).ptr;
1756
+
1757
+ if (info.base && (info.attr & BlkAttr.APPENDABLE ))
1758
+ {
1759
+ // calculate the extent of the array given the base.
1760
+ const size_t offset = (* p).ptr - __arrayStart(info);
1761
+ if (info.size >= PAGESIZE )
1712
1762
{
1713
- newdata = ( * p).ptr;
1714
- if (newlength > ( * p).length )
1763
+ // size of array is at the front of the block
1764
+ if ( ! __setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset) )
1715
1765
{
1716
- auto bic = isshared ? null : __getBlkInfo((* p).ptr);
1717
- auto info = bic ? * bic : GC .query((* p).ptr);
1718
-
1719
- // calculate the extent of the array given the base.
1720
- size_t offset = (* p).ptr - __arrayStart(info);
1721
- if (info.base && (info.attr & BlkAttr.APPENDABLE ))
1722
- {
1723
- if (info.size >= PAGESIZE )
1724
- {
1725
- // size of array is at the front of the block
1726
- if (! __setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
1727
- {
1728
- // check to see if it failed because there is not
1729
- // enough space
1730
- if (* (cast (size_t * )info.base) == size + offset)
1731
- {
1732
- // not enough space, try extending
1733
- auto extendsize = newsize + offset + LARGEPAD - info.size;
1734
- auto u = GC .extend(info.base, extendsize, extendsize);
1735
- if (u)
1736
- {
1737
- // extend worked, now try setting the length
1738
- // again.
1739
- info.size = u;
1740
- if (__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
1741
- {
1742
- if (! isshared)
1743
- __insertBlkInfoCache(info, bic);
1744
- goto L1 ;
1745
- }
1746
- }
1747
- }
1748
-
1749
- // couldn't do it, reallocate
1750
- goto L2 ;
1751
- }
1752
- else if (! isshared && ! bic)
1753
- {
1754
- // add this to the cache, it wasn't present previously.
1755
- __insertBlkInfoCache(info, null );
1756
- }
1757
- }
1758
- else if (! __setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
1759
- {
1760
- // could not resize in place
1761
- goto L2 ;
1762
- }
1763
- else if (! isshared && ! bic)
1764
- {
1765
- // add this to the cache, it wasn't present previously.
1766
- __insertBlkInfoCache(info, null );
1767
- }
1768
- }
1769
- else
1766
+ // check to see if it failed because there is not
1767
+ // enough space
1768
+ if (* (cast (size_t * )info.base) == size + offset)
1770
1769
{
1771
- // not appendable or not part of the heap yet.
1772
- if (info.base)
1770
+ // not enough space, try extending
1771
+ auto extendsize = newsize + offset + LARGEPAD - info.size;
1772
+ auto u = GC .extend(info.base, extendsize, extendsize);
1773
+ if (u)
1773
1774
{
1774
- L2 :
1775
- if (bic)
1775
+ // extend worked, now try setting the length
1776
+ // again.
1777
+ info.size = u;
1778
+ if (__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
1776
1779
{
1777
- // a chance that flags have changed since this was cached, we should fetch the most recent flags
1778
- info.attr = GC .getAttr(info.base) | BlkAttr.APPENDABLE ;
1780
+ if (! isshared)
1781
+ __insertBlkInfoCache(info, bic);
1782
+ doInitialize(newdata + size, newdata + newsize, tinext.initializer);
1783
+ * p = newdata[0 .. newlength];
1784
+ return * p;
1779
1785
}
1780
- info = __arrayAlloc(newsize, info, ti, tinext);
1781
- }
1782
- else
1783
- {
1784
- info = __arrayAlloc(newsize, ti, tinext);
1785
1786
}
1786
- __setArrayAllocLength(info, newsize, isshared, tinext);
1787
- if (! isshared)
1788
- __insertBlkInfoCache(info, bic);
1789
- newdata = cast (byte * )__arrayStart(info);
1790
- newdata[0 .. size] = (* p).ptr[0 .. size];
1791
-
1792
- // do postblit processing
1793
- __doPostblit(newdata, size, tinext);
1794
1787
}
1795
- L1 : ;
1788
+
1789
+ // couldn't do it, reallocate
1790
+ allocateAndCopy = true ;
1791
+ }
1792
+ else if (! isshared && ! bic)
1793
+ {
1794
+ // add this to the cache, it wasn't present previously.
1795
+ __insertBlkInfoCache(info, null );
1796
1796
}
1797
1797
}
1798
- else
1798
+ else if ( ! __setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
1799
1799
{
1800
- // length was zero, need to allocate
1801
- auto info = __arrayAlloc(newsize, ti, tinext);
1802
- __setArrayAllocLength(info, newsize, isshared, tinext);
1803
- if (! isshared)
1804
- __insertBlkInfoCache(info, null );
1805
- newdata = cast (byte * )__arrayStart(info);
1800
+ // could not resize in place
1801
+ allocateAndCopy = true ;
1806
1802
}
1807
-
1808
- auto q = initializer.ptr; // pointer to initializer
1809
-
1810
- if (newsize > size)
1803
+ else if (! isshared && ! bic)
1811
1804
{
1812
- if (initsize == 1 )
1813
- {
1814
- debug (PRINTF ) printf(" newdata = %p, size = %d, newsize = %d, *q = %d\n " , newdata, size, newsize, * cast (byte * )q);
1815
- memset(newdata + size, * cast (byte * )q, newsize - size);
1816
- }
1817
- else
1818
- {
1819
- for (size_t u = size; u < newsize; u += initsize)
1820
- {
1821
- memcpy(newdata + u, q, initsize);
1822
- }
1823
- }
1805
+ // add this to the cache, it wasn't present previously.
1806
+ __insertBlkInfoCache(info, null );
1824
1807
}
1825
1808
}
1826
1809
else
1810
+ allocateAndCopy = true ;
1811
+
1812
+ if (allocateAndCopy)
1827
1813
{
1828
- newdata = (* p).ptr;
1814
+ if (info.base)
1815
+ {
1816
+ if (bic)
1817
+ {
1818
+ // a chance that flags have changed since this was cached, we should fetch the most recent flags
1819
+ info.attr = GC .getAttr(info.base) | BlkAttr.APPENDABLE ;
1820
+ }
1821
+ info = __arrayAlloc(newsize, info, ti, tinext);
1822
+ }
1823
+ else
1824
+ {
1825
+ info = __arrayAlloc(newsize, ti, tinext);
1826
+ }
1827
+
1828
+ if (info.base is null )
1829
+ {
1830
+ onOutOfMemoryError();
1831
+ assert (0 );
1832
+ }
1833
+
1834
+ __setArrayAllocLength(info, newsize, isshared, tinext);
1835
+ if (! isshared)
1836
+ __insertBlkInfoCache(info, bic);
1837
+ newdata = cast (byte * )__arrayStart(info);
1838
+ newdata[0 .. size] = (* p).ptr[0 .. size];
1839
+
1840
+ /* Do postblit processing, as we are making a copy and the
1841
+ * original array may have references.
1842
+ * Note that this may throw.
1843
+ */
1844
+ __doPostblit(newdata, size, tinext);
1829
1845
}
1830
1846
1847
+ // Initialize the unused portion of the newly allocated space
1848
+ doInitialize(newdata + size, newdata + newsize, tinext.initializer);
1831
1849
* p = newdata[0 .. newlength];
1832
1850
return * p;
1833
-
1834
- Loverflow:
1835
- import core.exception : onOutOfMemoryError;
1836
- onOutOfMemoryError();
1837
- assert (0 );
1838
1851
}
1839
1852
1840
-
1841
1853
/**
1842
1854
* Append y[] to array x[]
1843
1855
*/
0 commit comments