@@ -1537,6 +1537,18 @@ namespace Js
1537
1537
Assert (this ->VerifyIsExtensible (scriptContext, false ) || this ->HasProperty (instance, propertyId)
1538
1538
|| JavascriptFunction::IsBuiltinProperty (instance, propertyId));
1539
1539
1540
+ // We could potentially need 2 new slots to hold getter/setter, try pre-reserve
1541
+ if (this ->GetSlotCapacity () - 2 < nextPropertyIndex)
1542
+ {
1543
+ if (this ->GetSlotCapacity () > MaxPropertyIndexSize - 2 )
1544
+ {
1545
+ return ConvertToBigDictionaryTypeHandler (instance)
1546
+ ->SetAccessors (instance, propertyId, getter, setter, flags);
1547
+ }
1548
+
1549
+ this ->EnsureSlotCapacity (instance, 2 );
1550
+ }
1551
+
1540
1552
DictionaryPropertyDescriptor<T>* descriptor;
1541
1553
if (this ->GetFlags () & IsPrototypeFlag)
1542
1554
{
@@ -1582,15 +1594,7 @@ namespace Js
1582
1594
// conversion from data-property to accessor property
1583
1595
if (descriptor->ConvertToGetterSetter (nextPropertyIndex))
1584
1596
{
1585
- if (this ->GetSlotCapacity () <= nextPropertyIndex)
1586
- {
1587
- if (this ->GetSlotCapacity () >= MaxPropertyIndexSize)
1588
- {
1589
- Throw::OutOfMemory ();
1590
- }
1591
-
1592
- this ->EnsureSlotCapacity (instance);
1593
- }
1597
+ AssertOrFailFast (this ->GetSlotCapacity () >= nextPropertyIndex); // pre-reserved 2 at entry
1594
1598
}
1595
1599
1596
1600
// DictionaryTypeHandlers are not supposed to be shared.
@@ -1673,15 +1677,7 @@ namespace Js
1673
1677
T getterIndex = ::Math::PostInc (nextPropertyIndex);
1674
1678
T setterIndex = ::Math::PostInc (nextPropertyIndex);
1675
1679
DictionaryPropertyDescriptor<T> newDescriptor (getterIndex, setterIndex);
1676
- if (this ->GetSlotCapacity () <= nextPropertyIndex)
1677
- {
1678
- if (this ->GetSlotCapacity () >= MaxPropertyIndexSize)
1679
- {
1680
- Throw::OutOfMemory ();
1681
- }
1682
-
1683
- this ->EnsureSlotCapacity (instance);
1684
- }
1680
+ AssertOrFailFast (this ->GetSlotCapacity () >= nextPropertyIndex); // pre-reserved 2 at entry
1685
1681
1686
1682
// DictionaryTypeHandlers are not supposed to be shared.
1687
1683
Assert (!GetIsOrMayBecomeShared ());
@@ -1782,6 +1778,18 @@ namespace Js
1782
1778
}
1783
1779
else if ((descriptor->Attributes & PropertyLetConstGlobal) != (attributes & PropertyLetConstGlobal))
1784
1780
{
1781
+ // We could potentially need 1 new slot by AddShadowedData(), try pre-reserve
1782
+ if (this ->GetSlotCapacity () <= nextPropertyIndex)
1783
+ {
1784
+ if (this ->GetSlotCapacity () >= MaxPropertyIndexSize)
1785
+ {
1786
+ return ConvertToBigDictionaryTypeHandler (instance)->SetPropertyWithAttributes (
1787
+ instance, propertyId, value, attributes, info, flags, possibleSideEffects);
1788
+ }
1789
+
1790
+ this ->EnsureSlotCapacity (instance);
1791
+ }
1792
+
1785
1793
bool addingLetConstGlobal = (attributes & PropertyLetConstGlobal) != 0 ;
1786
1794
1787
1795
if (addingLetConstGlobal)
@@ -1795,15 +1803,7 @@ namespace Js
1795
1803
1796
1804
descriptor->AddShadowedData (nextPropertyIndex, addingLetConstGlobal);
1797
1805
1798
- if (this ->GetSlotCapacity () <= nextPropertyIndex)
1799
- {
1800
- if (this ->GetSlotCapacity () >= MaxPropertyIndexSize)
1801
- {
1802
- Throw::OutOfMemory ();
1803
- }
1804
-
1805
- this ->EnsureSlotCapacity (instance);
1806
- }
1806
+ AssertOrFailFast (this ->GetSlotCapacity () >= nextPropertyIndex); // pre-reserved above
1807
1807
1808
1808
if (addingLetConstGlobal)
1809
1809
{
@@ -1891,15 +1891,14 @@ namespace Js
1891
1891
}
1892
1892
1893
1893
template <typename T>
1894
- void DictionaryTypeHandlerBase<T>::EnsureSlotCapacity(DynamicObject * instance)
1894
+ void DictionaryTypeHandlerBase<T>::EnsureSlotCapacity(DynamicObject * instance, T increment /* = 1 */ )
1895
1895
{
1896
1896
Assert (this ->GetSlotCapacity () < MaxPropertyIndexSize); // Otherwise we can't grow this handler's capacity. We should've evolved to Bigger handler or OOM.
1897
1897
1898
1898
// A Dictionary type is expected to have more properties
1899
1899
// grow exponentially rather linearly to avoid the realloc and moves,
1900
1900
// however use a small exponent to avoid waste
1901
- int newSlotCapacity;
1902
- newSlotCapacity = ::Math::Add (nextPropertyIndex, (T)1 );
1901
+ int newSlotCapacity = ::Math::Add (nextPropertyIndex, increment);
1903
1902
newSlotCapacity = ::Math::Add (newSlotCapacity, newSlotCapacity >> 2 );
1904
1903
if (newSlotCapacity > MaxPropertyIndexSize)
1905
1904
{
0 commit comments