Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 8c86106

Browse files
authored
Merge pull request #2217 from schveiguy/arraysetlength2
Followup to #2213, refactor the other arraysetlength merged-on-behalf-of: Mike Franklin <JinShil@users.noreply.github.com>
2 parents 753239f + 6859077 commit 8c86106

File tree

1 file changed

+160
-148
lines changed

1 file changed

+160
-148
lines changed

src/rt/lifetime.d

Lines changed: 160 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,195 +1649,207 @@ in
16491649
do
16501650
{
16511651
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;
16631653

16641654
debug(PRINTF)
16651655
{
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);
16671657
if (p)
1668-
printf("\tp.data = %p, p.length = %d\n", (*p).ptr, (*p).length);
1658+
printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length);
16691659
}
16701660

1671-
if (newlength)
1661+
if (newlength <= (*p).length)
16721662
{
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;
16761669

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;
16841683
}
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
16861690
{
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+
}
16881707

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);
16961717
}
16971718
else
16981719
{
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+
}
17001728

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);
17051737
}
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+
}
17071746

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);
17081750

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)
17121762
{
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))
17151765
{
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)
17701769
{
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)
17731774
{
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))
17761779
{
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;
17791785
}
1780-
info = __arrayAlloc(newsize, info, ti, tinext);
1781-
}
1782-
else
1783-
{
1784-
info = __arrayAlloc(newsize, ti, tinext);
17851786
}
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);
17941787
}
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);
17961796
}
17971797
}
1798-
else
1798+
else if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset))
17991799
{
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;
18061802
}
1807-
1808-
auto q = initializer.ptr; // pointer to initializer
1809-
1810-
if (newsize > size)
1803+
else if(!isshared && !bic)
18111804
{
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);
18241807
}
18251808
}
18261809
else
1810+
allocateAndCopy = true;
1811+
1812+
if (allocateAndCopy)
18271813
{
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);
18291845
}
18301846

1847+
// Initialize the unused portion of the newly allocated space
1848+
doInitialize(newdata + size, newdata + newsize, tinext.initializer);
18311849
*p = newdata[0 .. newlength];
18321850
return *p;
1833-
1834-
Loverflow:
1835-
import core.exception : onOutOfMemoryError;
1836-
onOutOfMemoryError();
1837-
assert(0);
18381851
}
18391852

1840-
18411853
/**
18421854
* Append y[] to array x[]
18431855
*/

0 commit comments

Comments
 (0)