Changeset 229516 in webkit


Ignore:
Timestamp:
Mar 11, 2018 10:45:49 AM (6 years ago)
Author:
fpizlo@apple.com
Message:

PerProcess<> should be safe by default
https://bugs.webkit.org/show_bug.cgi?id=183545

Reviewed by Yusuke Suzuki.

This makes PerProcess<> safe by default, so we don't need SafePerProcess<>.

The new PerProcess<> design relies on a hash-consing mechanism for PerProcess<> storage based
on the PRETTY_FUNCTION from inside PerProcess<>, which captures the instantiated type in
the string. Therefore, this can be used to runtime-coalesce PerProcess<> instances based on
type.

I expect this to be perf-neutral. It's an important prerequisite to more bmalloc work, since I
don't want to have more PerProcess<> vs SafePerProcess<> bugs, and SafePerProcess<> can't be
used for everything (I don't see how to use it for isoheaps).

  • CMakeLists.txt:
  • bmalloc.xcodeproj/project.pbxproj:
  • bmalloc/Heap.cpp:

(bmalloc::Heap::Heap):

  • bmalloc/IsoDirectoryInlines.h:

(bmalloc::passedNumPages>::takeFirstEligible):
(bmalloc::passedNumPages>::didBecome):

  • bmalloc/PerProcess.cpp: Added.

(bmalloc::stringHash):
(bmalloc::allocate):
(bmalloc::getPerProcessData):

  • bmalloc/PerProcess.h:

(bmalloc::PerProcess::mutex):
(bmalloc::PerProcess::coalesce):
(bmalloc::PerProcess::getSlowCase):
(): Deleted.

  • bmalloc/Scavenger.cpp:
  • bmalloc/Scavenger.h:
  • bmalloc/bmalloc.cpp:

(bmalloc::api::scavenge):
(bmalloc::api::setScavengerThreadQOSClass):

Location:
trunk/Source/bmalloc
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/bmalloc/CMakeLists.txt

    r228108 r229516  
    2626    bmalloc/Logging.cpp
    2727    bmalloc/ObjectType.cpp
     28    bmalloc/PerProcess.cpp
    2829    bmalloc/Scavenger.cpp
    2930    bmalloc/StaticMutex.cpp
  • trunk/Source/bmalloc/ChangeLog

    r229504 r229516  
     12018-03-10  Filip Pizlo  <fpizlo@apple.com>
     2
     3        PerProcess<> should be safe by default
     4        https://bugs.webkit.org/show_bug.cgi?id=183545
     5
     6        Reviewed by Yusuke Suzuki.
     7       
     8        This makes PerProcess<> safe by default, so we don't need SafePerProcess<>.
     9       
     10        The new PerProcess<> design relies on a hash-consing mechanism for PerProcess<> storage based
     11        on the __PRETTY_FUNCTION__ from inside PerProcess<>, which captures the instantiated type in
     12        the string. Therefore, this can be used to runtime-coalesce PerProcess<> instances based on
     13        type.
     14       
     15        I expect this to be perf-neutral. It's an important prerequisite to more bmalloc work, since I
     16        don't want to have more PerProcess<> vs SafePerProcess<> bugs, and SafePerProcess<> can't be
     17        used for everything (I don't see how to use it for isoheaps).
     18
     19        * CMakeLists.txt:
     20        * bmalloc.xcodeproj/project.pbxproj:
     21        * bmalloc/Heap.cpp:
     22        (bmalloc::Heap::Heap):
     23        * bmalloc/IsoDirectoryInlines.h:
     24        (bmalloc::passedNumPages>::takeFirstEligible):
     25        (bmalloc::passedNumPages>::didBecome):
     26        * bmalloc/PerProcess.cpp: Added.
     27        (bmalloc::stringHash):
     28        (bmalloc::allocate):
     29        (bmalloc::getPerProcessData):
     30        * bmalloc/PerProcess.h:
     31        (bmalloc::PerProcess::mutex):
     32        (bmalloc::PerProcess::coalesce):
     33        (bmalloc::PerProcess::getSlowCase):
     34        (): Deleted.
     35        * bmalloc/Scavenger.cpp:
     36        * bmalloc/Scavenger.h:
     37        * bmalloc/bmalloc.cpp:
     38        (bmalloc::api::scavenge):
     39        (bmalloc::api::setScavengerThreadQOSClass):
     40
    1412018-03-10  Commit Queue  <commit-queue@webkit.org>
    242
  • trunk/Source/bmalloc/bmalloc.xcodeproj/project.pbxproj

    r228108 r229516  
    2222
    2323/* Begin PBXBuildFile section */
     24                0F26A7A5205483130090A141 /* PerProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F26A7A42054830D0090A141 /* PerProcess.cpp */; };
    2425                0F5167741FAD685C008236A8 /* bmalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5167731FAD6852008236A8 /* bmalloc.cpp */; };
    2526                0F5549EF1FB54704007FF75A /* IsoPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5549EE1FB54701007FF75A /* IsoPage.cpp */; };
     
    175176
    176177/* Begin PBXFileReference section */
     178                0F26A7A42054830D0090A141 /* PerProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PerProcess.cpp; path = bmalloc/PerProcess.cpp; sourceTree = "<group>"; };
    177179                0F5167731FAD6852008236A8 /* bmalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bmalloc.cpp; path = bmalloc/bmalloc.cpp; sourceTree = "<group>"; };
    178180                0F5549EE1FB54701007FF75A /* IsoPage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IsoPage.cpp; path = bmalloc/IsoPage.cpp; sourceTree = "<group>"; };
     
    522524                                14C8992A1CC485E70027A057 /* Map.h */,
    523525                                144DCED617A649D90093B2F2 /* Mutex.h */,
     526                                0F26A7A42054830D0090A141 /* PerProcess.cpp */,
    524527                                0F5BF1481F22A8D80029D91D /* PerHeapKind.h */,
    525528                                14446A0717A61FA400F9EA1D /* PerProcess.h */,
     
    769772                                6599C5CC1EC3F15900A2F7BB /* AvailableMemory.cpp in Sources */,
    770773                                14F271C418EA397B008C152F /* Cache.cpp in Sources */,
     774                                0F26A7A5205483130090A141 /* PerProcess.cpp in Sources */,
    771775                                14F271C518EA397E008C152F /* Deallocator.cpp in Sources */,
    772776                                142B44361E2839E7001DA6E9 /* DebugHeap.cpp in Sources */,
  • trunk/Source/bmalloc/bmalloc/CryptoRandom.cpp

    r224537 r229516  
    5454
    5555namespace bmalloc {
    56 
    57 namespace {
    5856
    5957class ARC4Stream {
     
    181179}
    182180
    183 }
    184 
    185181void cryptoRandom(void* buffer, size_t length)
    186182{
  • trunk/Source/bmalloc/bmalloc/Heap.cpp

    r228107 r229516  
    6565    }
    6666   
    67     m_scavenger = SafePerProcess<Scavenger>::get();
     67    m_scavenger = PerProcess<Scavenger>::get();
    6868}
    6969
  • trunk/Source/bmalloc/bmalloc/IsoDirectoryInlines.h

    r228107 r229516  
    5252        return EligibilityKind::Full;
    5353   
    54     Scavenger& scavenger = *SafePerProcess<Scavenger>::get();
     54    Scavenger& scavenger = *PerProcess<Scavenger>::get();
    5555    scavenger.didStartGrowing();
    5656   
     
    101101            fprintf(stderr, "%p: %p did become empty.\n", this, page);
    102102        m_empty[pageIndex] = true;
    103         SafePerProcess<Scavenger>::get()->schedule(IsoPageBase::pageSize);
     103        PerProcess<Scavenger>::get()->schedule(IsoPageBase::pageSize);
    104104        return;
    105105    }
  • trunk/Source/bmalloc/bmalloc/PerProcess.h

    r228107 r229516  
    3939// Object will be instantiated only once, even in the face of concurrency.
    4040//
    41 // WARNING: PerProcess<T> does not export its storage. So in actuality when
    42 // used in multiple libraries / images it ends up being per-image. To truly
    43 // declare a per-process singleton use SafePerProcess<T>.
    44 //
    4541// NOTE: If you observe global side-effects of the Object constructor, be
    4642// sure to lock the Object mutex. For example:
     
    5551// Object* object = PerProcess<Object>::get(lock);
    5652// if (globalFlag) { ... } // OK.
     53
     54struct PerProcessData {
     55    const char* disambiguator;
     56    void* memory;
     57    size_t size;
     58    size_t alignment;
     59    StaticMutex mutex;
     60    bool isInitialized;
     61    PerProcessData* next;
     62};
     63
     64constexpr unsigned stringHash(const char* string)
     65{
     66    unsigned result = 5381;
     67    while (char c = *string++)
     68        result = result * 33 + c;
     69    return result;
     70}
     71
     72BEXPORT PerProcessData* getPerProcessData(unsigned disambiguatorHash, const char* disambiguator, size_t size, size_t alignment);
    5773
    5874template<typename T>
     
    7288    }
    7389   
    74     static StaticMutex& mutex() { return s_mutex; }
     90    static StaticMutex& mutex()
     91    {
     92        if (!s_data)
     93            coalesce();
     94        return s_data->mutex;
     95    }
    7596
    7697private:
     98    static void coalesce()
     99    {
     100        if (s_data)
     101            return;
     102       
     103        const char* disambiguator = __PRETTY_FUNCTION__;
     104        s_data = getPerProcessData(stringHash(disambiguator), disambiguator, sizeof(T), std::alignment_of<T>::value);
     105    }
     106   
    77107    BNO_INLINE static T* getSlowCase()
    78108    {
    79         std::lock_guard<StaticMutex> lock(s_mutex);
    80         if (!s_object.load(std::memory_order_consume)) {
    81             T* t = new (&s_memory) T(lock);
    82             s_object.store(t, std::memory_order_release);
     109        std::lock_guard<StaticMutex> lock(mutex());
     110        if (!s_object.load()) {
     111            if (s_data->isInitialized)
     112                s_object.store(static_cast<T*>(s_data->memory));
     113            else {
     114                T* t = new (s_data->memory) T(lock);
     115                s_object.store(t);
     116                s_data->isInitialized = true;
     117            }
    83118        }
    84         return s_object.load(std::memory_order_consume);
     119        return s_object.load();
    85120    }
    86121
    87122    static std::atomic<T*> s_object;
    88     static StaticMutex s_mutex;
    89 
    90     typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type Memory;
    91     static Memory s_memory;
     123    static PerProcessData* s_data;
    92124};
    93125
     
    96128
    97129template<typename T>
    98 StaticMutex PerProcess<T>::s_mutex;
    99 
    100 template<typename T>
    101 typename PerProcess<T>::Memory PerProcess<T>::s_memory;
    102 
    103 
    104 // SafePerProcess<T> behaves like PerProcess<T>, but its usage
    105 // requires DECLARE/DEFINE macros that export symbols that allow for
    106 // a single shared instance is across images in the process.
    107 
    108 template<typename T> struct SafePerProcessStorageTraits;
    109 
    110 template<typename T>
    111 class BEXPORT SafePerProcess {
    112 public:
    113     using Storage = typename SafePerProcessStorageTraits<T>::Storage;
    114 
    115     static T* get()
    116     {
    117         T* object = getFastCase();
    118         if (!object)
    119             return getSlowCase();
    120         return object;
    121     }
    122 
    123     static T* getFastCase()
    124     {
    125         return (Storage::s_object).load(std::memory_order_relaxed);
    126     }
    127 
    128     static StaticMutex& mutex() { return Storage::s_mutex; }
    129 
    130     using Memory = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
    131 
    132 private:
    133     BNO_INLINE static T* getSlowCase()
    134     {
    135         std::lock_guard<StaticMutex> lock(Storage::s_mutex);
    136         if (!Storage::s_object.load(std::memory_order_consume)) {
    137             T* t = new (&Storage::s_memory) T(lock);
    138             Storage::s_object.store(t, std::memory_order_release);
    139         }
    140         return Storage::s_object.load(std::memory_order_consume);
    141     }
    142 };
    143 
    144 #define DECLARE_SAFE_PER_PROCESS_STORAGE(Type) \
    145     template<> struct SafePerProcessStorageTraits<Type> { \
    146         struct BEXPORT Storage { \
    147             BEXPORT static std::atomic<Type*> s_object; \
    148             BEXPORT static StaticMutex s_mutex; \
    149             BEXPORT static SafePerProcess<Type>::Memory s_memory; \
    150         }; \
    151     };
    152 
    153 #define DEFINE_SAFE_PER_PROCESS_STORAGE(Type) \
    154     std::atomic<Type*> SafePerProcessStorageTraits<Type>::Storage::s_object; \
    155     StaticMutex SafePerProcessStorageTraits<Type>::Storage::s_mutex; \
    156     SafePerProcess<Type>::Memory SafePerProcessStorageTraits<Type>::Storage::s_memory;
     130PerProcessData* PerProcess<T>::s_data;
    157131
    158132} // namespace bmalloc
  • trunk/Source/bmalloc/bmalloc/Scavenger.cpp

    r228107 r229516  
    3232
    3333namespace bmalloc {
    34 
    35 DEFINE_SAFE_PER_PROCESS_STORAGE(Scavenger);
    3634
    3735Scavenger::Scavenger(std::lock_guard<StaticMutex>&)
  • trunk/Source/bmalloc/bmalloc/Scavenger.h

    r228107 r229516  
    9494};
    9595
    96 DECLARE_SAFE_PER_PROCESS_STORAGE(Scavenger);
    97 
    9896} // namespace bmalloc
    9997
  • trunk/Source/bmalloc/bmalloc/bmalloc.cpp

    r228107 r229516  
    7474    scavengeThisThread();
    7575
    76     SafePerProcess<Scavenger>::get()->scavenge();
     76    PerProcess<Scavenger>::get()->scavenge();
    7777}
    7878
     
    8888{
    8989    std::unique_lock<StaticMutex> lock(Heap::mutex());
    90     SafePerProcess<Scavenger>::get()->setScavengerThreadQOSClass(overrideClass);
     90    PerProcess<Scavenger>::get()->setScavengerThreadQOSClass(overrideClass);
    9191}
    9292#endif
Note: See TracChangeset for help on using the changeset viewer.