@@ -81,9 +81,13 @@ void SegmentedArray::Segment::setLength(Runtime *runtime, uint32_t newLength) {
8181 data_ + newLength,
8282 HermesValue::encodeEmptyValue (),
8383 &runtime->getHeap ());
84+ length_.store (newLength, std::memory_order_release);
85+ } else if (newLength < len) {
86+ // If length is decreasing a write barrier needs to be done.
87+ GCHermesValue::rangeUnreachableWriteBarrier (
88+ data_ + newLength, data_ + len, &runtime->getHeap ());
89+ length_.store (newLength, std::memory_order_release);
8490 }
85- // If length is decreasing nothing special needs to be done.
86- setLengthWithoutFilling (newLength);
8791}
8892
8993VTable SegmentedArray::vt (
@@ -332,8 +336,9 @@ ExecutionStatus SegmentedArray::growLeft(
332336 return ExecutionStatus::EXCEPTION ;
333337 }
334338 PseudoHandle<SegmentedArray> newSegmentedArray = std::move (*arrRes);
335- // Don't fill with empty values, most will be copied in.
336- newSegmentedArray = increaseSize</* Fill*/ false >(
339+ // If it's not a concurrent GC, don't fill with empty values, most will be
340+ // copied in.
341+ newSegmentedArray = increaseSize</* Fill*/ kConcurrentGC >(
337342 runtime, std::move (newSegmentedArray), newSize);
338343 // Fill the beginning of the new array with empty values.
339344 GCHermesValue::uninitialized_fill (
@@ -389,6 +394,9 @@ void SegmentedArray::increaseSizeWithinCapacity(
389394 Runtime *runtime,
390395 size_type amount,
391396 bool fill) {
397+ assert (
398+ !kConcurrentGC ||
399+ fill && " If kConcurrentGC is true, fill must also be true" );
392400 // This function has the same logic as increaseSize, but removes some
393401 // complexity from avoiding dealing with alllocations.
394402 const auto empty = HermesValue::encodeEmptyValue ();
@@ -435,6 +443,9 @@ PseudoHandle<SegmentedArray> SegmentedArray::increaseSize(
435443 Runtime *runtime,
436444 PseudoHandle<SegmentedArray> self,
437445 size_type amount) {
446+ assert (
447+ !kConcurrentGC ||
448+ Fill && " If kConcurrentGC is true, fill must also be true" );
438449 const auto empty = HermesValue::encodeEmptyValue ();
439450 const auto currSize = self->size ();
440451 const auto finalSize = currSize + amount;
@@ -530,18 +541,26 @@ PseudoHandle<SegmentedArray> SegmentedArray::increaseSize(
530541}
531542
532543void SegmentedArray::decreaseSize (Runtime *runtime, size_type amount) {
533- assert (amount <= size () && " Cannot decrease size past zero" );
534- const auto finalSize = size () - amount;
535- if (finalSize <= kValueToSegmentThreshold ) {
536- // Just adjust the field and exit, no segments to compress.
537- numSlotsUsed_.store (finalSize, std::memory_order_release);
538- return ;
544+ const auto initialSize = size ();
545+ const auto initialNumSlots = numSlotsUsed_.load (std::memory_order_relaxed);
546+ assert (amount <= initialSize && " Cannot decrease size past zero" );
547+ const auto finalSize = initialSize - amount;
548+ const auto finalNumSlots = numSlotsForCapacity (finalSize);
549+ assert (
550+ finalNumSlots <= initialNumSlots &&
551+ " Should not be increasing the number of slots" );
552+ if (finalSize > kValueToSegmentThreshold ) {
553+ // Set the new last used segment's length to be the leftover.
554+ segmentAt (toSegment (finalSize - 1 ))
555+ ->setLength (runtime, toInterior (finalSize - 1 ) + 1 );
539556 }
540- // Set the new last used segment's length to be the leftover.
541- segmentAt (toSegment (finalSize - 1 ))
542- ->setLength (runtime, toInterior (finalSize - 1 ) + 1 );
543- numSlotsUsed_.store (
544- numSlotsForCapacity (finalSize), std::memory_order_release);
557+ // Before shrinking, do a snapshot write barrier for the elements being
558+ // removed.
559+ GCHermesValue::rangeUnreachableWriteBarrier (
560+ inlineStorage () + finalNumSlots,
561+ inlineStorage () + initialNumSlots,
562+ &runtime->getHeap ());
563+ numSlotsUsed_.store (finalNumSlots, std::memory_order_release);
545564}
546565
547566gcheapsize_t SegmentedArray::_trimSizeCallback (const GCCell *cell) {
0 commit comments