@@ -500,86 +500,24 @@ PLDHashEntryHdr* PLDHashTable::Search(const void* aKey) const {
500
500
}
501
501
502
502
PLDHashEntryHdr* PLDHashTable::Add (const void * aKey,
503
- const mozilla::fallible_t &) {
504
- #ifdef MOZ_HASH_TABLE_CHECKS_ENABLED
505
- AutoWriteOp op (mChecker );
506
- #endif
507
-
508
- // Allocate the entry storage if it hasn't already been allocated.
509
- if (!mEntryStore .IsAllocated ()) {
510
- uint32_t nbytes;
511
- // We already checked this in the constructor, so it must still be true.
512
- MOZ_RELEASE_ASSERT (
513
- SizeOfEntryStore (CapacityFromHashShift (), mEntrySize , &nbytes));
514
- mEntryStore .Set ((char *)calloc (1 , nbytes), &mGeneration );
515
- if (!mEntryStore .IsAllocated ()) {
516
- return nullptr ;
517
- }
518
- }
519
-
520
- // If alpha is >= .75, grow or compress the table. If aKey is already in the
521
- // table, we may grow once more than necessary, but only if we are on the
522
- // edge of being overloaded.
523
- uint32_t capacity = Capacity ();
524
- if (mEntryCount + mRemovedCount >= MaxLoad (capacity)) {
525
- // Compress if a quarter or more of all entries are removed.
526
- int deltaLog2;
527
- if (mRemovedCount >= capacity >> 2 ) {
528
- deltaLog2 = 0 ;
529
- } else {
530
- deltaLog2 = 1 ;
531
- }
532
-
533
- // Grow or compress the table. If ChangeTable() fails, allow overloading up
534
- // to the secondary max. Once we hit the secondary max, return null.
535
- if (!ChangeTable (deltaLog2) &&
536
- mEntryCount + mRemovedCount >= MaxLoadOnGrowthFailure (capacity)) {
537
- return nullptr ;
538
- }
503
+ const mozilla::fallible_t & aFallible) {
504
+ auto maybeEntryHandle = MakeEntryHandle (aKey, aFallible);
505
+ if (!maybeEntryHandle) {
506
+ return nullptr ;
539
507
}
540
-
541
- // Look for entry after possibly growing, so we don't have to add it,
542
- // then skip it while growing the table and re-add it after.
543
- PLDHashNumber keyHash = ComputeKeyHash (aKey);
544
- Slot slot = SearchTable<ForAdd>(
545
- aKey, keyHash, [&](Slot& found) -> Slot { return found; },
546
- [&]() -> Slot {
547
- MOZ_CRASH (" Nope" );
548
- return Slot (nullptr , nullptr );
549
- });
550
- if (!slot.IsLive ()) {
551
- // Initialize the slot, indicating that it's no longer free.
552
- if (slot.IsRemoved ()) {
553
- mRemovedCount --;
554
- keyHash |= kCollisionFlag ;
555
- }
508
+ return maybeEntryHandle->OrInsert ([&aKey, this ](PLDHashEntryHdr* entry) {
556
509
if (mOps ->initEntry ) {
557
- mOps ->initEntry (slot. ToEntry () , aKey);
510
+ mOps ->initEntry (entry , aKey);
558
511
}
559
- slot.SetKeyHash (keyHash);
560
- mEntryCount ++;
561
- }
562
-
563
- return slot.ToEntry ();
512
+ });
564
513
}
565
514
566
515
PLDHashEntryHdr* PLDHashTable::Add (const void * aKey) {
567
- PLDHashEntryHdr* entry = Add (aKey, fallible);
568
- if (!entry) {
569
- if (!mEntryStore .IsAllocated ()) {
570
- // We OOM'd while allocating the initial entry storage.
571
- uint32_t nbytes;
572
- (void )SizeOfEntryStore (CapacityFromHashShift (), mEntrySize , &nbytes);
573
- NS_ABORT_OOM (nbytes);
574
- } else {
575
- // We failed to resize the existing entry storage, either due to OOM or
576
- // because we exceeded the maximum table capacity or size; report it as
577
- // an OOM. The multiplication by 2 gets us the size we tried to allocate,
578
- // which is double the current size.
579
- NS_ABORT_OOM (2 * EntrySize () * EntryCount());
516
+ return MakeEntryHandle (aKey).OrInsert ([&aKey, this ](PLDHashEntryHdr* entry) {
517
+ if (mOps ->initEntry ) {
518
+ mOps ->initEntry (entry, aKey);
580
519
}
581
- }
582
- return entry;
520
+ });
583
521
}
584
522
585
523
void PLDHashTable::Remove (const void * aKey) {
@@ -671,6 +609,129 @@ size_t PLDHashTable::ShallowSizeOfIncludingThis(
671
609
return aMallocSizeOf (this ) + ShallowSizeOfExcludingThis (aMallocSizeOf);
672
610
}
673
611
612
+ mozilla::Maybe<PLDHashTable::EntryHandle> PLDHashTable::MakeEntryHandle (
613
+ const void * aKey, const mozilla::fallible_t &) {
614
+ #ifdef MOZ_HASH_TABLE_CHECKS_ENABLED
615
+ mChecker .StartWriteOp ();
616
+ auto endWriteOp = MakeScopeExit ([&] { mChecker .EndWriteOp (); });
617
+ #endif
618
+
619
+ // Allocate the entry storage if it hasn't already been allocated.
620
+ if (!mEntryStore .IsAllocated ()) {
621
+ uint32_t nbytes;
622
+ // We already checked this in the constructor, so it must still be true.
623
+ MOZ_RELEASE_ASSERT (
624
+ SizeOfEntryStore (CapacityFromHashShift (), mEntrySize , &nbytes));
625
+ mEntryStore .Set ((char *)calloc (1 , nbytes), &mGeneration );
626
+ if (!mEntryStore .IsAllocated ()) {
627
+ return Nothing ();
628
+ }
629
+ }
630
+
631
+ // If alpha is >= .75, grow or compress the table. If aKey is already in the
632
+ // table, we may grow once more than necessary, but only if we are on the
633
+ // edge of being overloaded.
634
+ uint32_t capacity = Capacity ();
635
+ if (mEntryCount + mRemovedCount >= MaxLoad (capacity)) {
636
+ // Compress if a quarter or more of all entries are removed.
637
+ int deltaLog2 = 1 ;
638
+ if (mRemovedCount >= capacity >> 2 ) {
639
+ deltaLog2 = 0 ;
640
+ }
641
+
642
+ // Grow or compress the table. If ChangeTable() fails, allow overloading up
643
+ // to the secondary max. Once we hit the secondary max, return null.
644
+ if (!ChangeTable (deltaLog2) &&
645
+ mEntryCount + mRemovedCount >= MaxLoadOnGrowthFailure (capacity)) {
646
+ return Nothing ();
647
+ }
648
+ }
649
+
650
+ // Look for entry after possibly growing, so we don't have to add it,
651
+ // then skip it while growing the table and re-add it after.
652
+ PLDHashNumber keyHash = ComputeKeyHash (aKey);
653
+ Slot slot = SearchTable<ForAdd>(
654
+ aKey, keyHash, [](Slot& found) -> Slot { return found; },
655
+ []() -> Slot {
656
+ MOZ_CRASH (" Nope" );
657
+ return Slot (nullptr , nullptr );
658
+ });
659
+
660
+ // The `EntryHandle` will handle ending the write op when it is destroyed.
661
+ #ifdef MOZ_HASH_TABLE_CHECKS_ENABLED
662
+ endWriteOp.release ();
663
+ #endif
664
+
665
+ return Some (EntryHandle{this , keyHash, slot});
666
+ }
667
+
668
+ PLDHashTable::EntryHandle PLDHashTable::MakeEntryHandle (const void * aKey) {
669
+ auto res = MakeEntryHandle (aKey, fallible);
670
+ if (!res) {
671
+ if (!mEntryStore .IsAllocated ()) {
672
+ // We OOM'd while allocating the initial entry storage.
673
+ uint32_t nbytes;
674
+ (void )SizeOfEntryStore (CapacityFromHashShift (), mEntrySize , &nbytes);
675
+ NS_ABORT_OOM (nbytes);
676
+ } else {
677
+ // We failed to resize the existing entry storage, either due to OOM or
678
+ // because we exceeded the maximum table capacity or size; report it as
679
+ // an OOM. The multiplication by 2 gets us the size we tried to allocate,
680
+ // which is double the current size.
681
+ NS_ABORT_OOM (2 * EntrySize () * EntryCount());
682
+ }
683
+ }
684
+ return res.extract();
685
+ }
686
+
687
+ PLDHashTable::EntryHandle::EntryHandle (PLDHashTable* aTable,
688
+ PLDHashNumber aKeyHash, Slot aSlot)
689
+ : mTable (aTable), mKeyHash (aKeyHash), mSlot (aSlot) {}
690
+
691
+ PLDHashTable::EntryHandle::EntryHandle (EntryHandle&& aOther) noexcept
692
+ : mTable (std::exchange (aOther.mTable , nullptr )),
693
+ mKeyHash (aOther.mKeyHash ),
694
+ mSlot (aOther.mSlot ) {}
695
+
696
+ PLDHashTable::EntryHandle::~EntryHandle () {
697
+ if (!mTable ) {
698
+ return ;
699
+ }
700
+
701
+ // If our slot is empty when this `EntryHandle` is destroyed, we may want to
702
+ // resize our table, as we just removed an entry.
703
+ if (!HasEntry ()) {
704
+ mTable ->ShrinkIfAppropriate ();
705
+ }
706
+ #ifdef MOZ_HASH_TABLE_CHECKS_ENABLED
707
+ mTable ->mChecker .EndWriteOp ();
708
+ #endif
709
+ }
710
+
711
+ void PLDHashTable::EntryHandle::Remove () {
712
+ MOZ_ASSERT (HasEntry ());
713
+
714
+ mTable ->RawRemove (mSlot );
715
+ }
716
+
717
+ void PLDHashTable::EntryHandle::OrRemove () {
718
+ if (HasEntry ()) {
719
+ Remove ();
720
+ }
721
+ }
722
+
723
+ void PLDHashTable::EntryHandle::OccupySlot () {
724
+ MOZ_ASSERT (!HasEntry ());
725
+
726
+ PLDHashNumber keyHash = mKeyHash ;
727
+ if (mSlot .IsRemoved ()) {
728
+ mTable ->mRemovedCount --;
729
+ keyHash |= kCollisionFlag ;
730
+ }
731
+ mSlot .SetKeyHash (keyHash);
732
+ mTable ->mEntryCount ++;
733
+ }
734
+
674
735
PLDHashTable::Iterator::Iterator (Iterator&& aOther)
675
736
: mTable (aOther.mTable ),
676
737
mCurrent (aOther.mCurrent ),
0 commit comments