Diff
Modified: trunk/Source/bmalloc/CMakeLists.txt (229515 => 229516)
--- trunk/Source/bmalloc/CMakeLists.txt 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/CMakeLists.txt 2018-03-11 17:45:49 UTC (rev 229516)
@@ -25,6 +25,7 @@
bmalloc/LargeMap.cpp
bmalloc/Logging.cpp
bmalloc/ObjectType.cpp
+ bmalloc/PerProcess.cpp
bmalloc/Scavenger.cpp
bmalloc/StaticMutex.cpp
bmalloc/VMHeap.cpp
Modified: trunk/Source/bmalloc/ChangeLog (229515 => 229516)
--- trunk/Source/bmalloc/ChangeLog 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/ChangeLog 2018-03-11 17:45:49 UTC (rev 229516)
@@ -1,3 +1,43 @@
+2018-03-10 Filip Pizlo <fpi...@apple.com>
+
+ 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):
+
2018-03-10 Commit Queue <commit-qu...@webkit.org>
Unreviewed, rolling out r229436.
Modified: trunk/Source/bmalloc/bmalloc/CryptoRandom.cpp (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/CryptoRandom.cpp 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/CryptoRandom.cpp 2018-03-11 17:45:49 UTC (rev 229516)
@@ -54,8 +54,6 @@
namespace bmalloc {
-namespace {
-
class ARC4Stream {
public:
ARC4Stream();
@@ -180,8 +178,6 @@
}
}
-}
-
void cryptoRandom(void* buffer, size_t length)
{
PerProcess<ARC4RandomNumberGenerator>::get()->randomValues(buffer, length);
Modified: trunk/Source/bmalloc/bmalloc/Heap.cpp (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/Heap.cpp 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/Heap.cpp 2018-03-11 17:45:49 UTC (rev 229516)
@@ -64,7 +64,7 @@
#endif
}
- m_scavenger = SafePerProcess<Scavenger>::get();
+ m_scavenger = PerProcess<Scavenger>::get();
}
bool Heap::usingGigacage()
Modified: trunk/Source/bmalloc/bmalloc/IsoDirectoryInlines.h (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/IsoDirectoryInlines.h 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/IsoDirectoryInlines.h 2018-03-11 17:45:49 UTC (rev 229516)
@@ -51,7 +51,7 @@
if (pageIndex >= numPages)
return EligibilityKind::Full;
- Scavenger& scavenger = *SafePerProcess<Scavenger>::get();
+ Scavenger& scavenger = *PerProcess<Scavenger>::get();
scavenger.didStartGrowing();
IsoPage<Config>* page = m_pages[pageIndex];
@@ -100,7 +100,7 @@
if (verbose)
fprintf(stderr, "%p: %p did become empty.\n", this, page);
m_empty[pageIndex] = true;
- SafePerProcess<Scavenger>::get()->schedule(IsoPageBase::pageSize);
+ PerProcess<Scavenger>::get()->schedule(IsoPageBase::pageSize);
return;
}
BCRASH();
Added: trunk/Source/bmalloc/bmalloc/PerProcess.cpp (0 => 229516)
--- trunk/Source/bmalloc/bmalloc/PerProcess.cpp (rev 0)
+++ trunk/Source/bmalloc/bmalloc/PerProcess.cpp 2018-03-11 17:45:49 UTC (rev 229516)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PerProcess.h"
+
+#include "VMAllocate.h"
+
+namespace bmalloc {
+
+static constexpr unsigned tableSize = 100;
+static constexpr bool verbose = false;
+
+static StaticMutex s_mutex;
+
+static char* s_bumpBase;
+static size_t s_bumpOffset;
+static size_t s_bumpLimit;
+
+static PerProcessData* s_table[tableSize];
+
+// Returns zero-filled memory by virtual of using vmAllocate.
+static void* allocate(size_t size, size_t alignment)
+{
+ s_bumpOffset = roundUpToMultipleOf(alignment, s_bumpOffset);
+ void* result = s_bumpBase + s_bumpOffset;
+ s_bumpOffset += size;
+ if (s_bumpOffset <= s_bumpLimit)
+ return result;
+
+ size_t allocationSize = vmSize(size);
+ void* allocation = vmAllocate(allocationSize);
+ s_bumpBase = static_cast<char*>(allocation);
+ s_bumpOffset = 0;
+ s_bumpLimit = allocationSize;
+ return allocate(size, alignment);
+}
+
+PerProcessData* getPerProcessData(unsigned hash, const char* disambiguator, size_t size, size_t alignment)
+{
+ std::lock_guard<StaticMutex> lock(s_mutex);
+
+ PerProcessData*& bucket = s_table[hash % tableSize];
+
+ for (PerProcessData* data = "" data; data = "" {
+ if (!strcmp(data->disambiguator, disambiguator)) {
+ if (verbose)
+ fprintf(stderr, "%d: Using existing %s\n", getpid(), disambiguator);
+ RELEASE_BASSERT(data->size == size);
+ RELEASE_BASSERT(data->alignment == alignment);
+ return data;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "%d: Creating new %s\n", getpid(), disambiguator);
+ void* rawDataPtr = allocate(sizeof(PerProcessData), std::alignment_of<PerProcessData>::value);
+ PerProcessData* data = ""
+ data->disambiguator = disambiguator;
+ data->memory = allocate(size, alignment);
+ data->size = size;
+ data->alignment = alignment;
+ data->next = bucket;
+ bucket = data;
+ return data;
+}
+
+} // namespace bmalloc
+
Modified: trunk/Source/bmalloc/bmalloc/PerProcess.h (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/PerProcess.h 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/PerProcess.h 2018-03-11 17:45:49 UTC (rev 229516)
@@ -38,10 +38,6 @@
//
// Object will be instantiated only once, even in the face of concurrency.
//
-// WARNING: PerProcess<T> does not export its storage. So in actuality when
-// used in multiple libraries / images it ends up being per-image. To truly
-// declare a per-process singleton use SafePerProcess<T>.
-//
// NOTE: If you observe global side-effects of the Object constructor, be
// sure to lock the Object mutex. For example:
//
@@ -55,6 +51,26 @@
// Object* object = PerProcess<Object>::get(lock);
// if (globalFlag) { ... } // OK.
+struct PerProcessData {
+ const char* disambiguator;
+ void* memory;
+ size_t size;
+ size_t alignment;
+ StaticMutex mutex;
+ bool isInitialized;
+ PerProcessData* next;
+};
+
+constexpr unsigned stringHash(const char* string)
+{
+ unsigned result = 5381;
+ while (char c = *string++)
+ result = result * 33 + c;
+ return result;
+}
+
+BEXPORT PerProcessData* getPerProcessData(unsigned disambiguatorHash, const char* disambiguator, size_t size, size_t alignment);
+
template<typename T>
class PerProcess {
public:
@@ -71,24 +87,40 @@
return s_object.load(std::memory_order_relaxed);
}
- static StaticMutex& mutex() { return s_mutex; }
+ static StaticMutex& mutex()
+ {
+ if (!s_data)
+ coalesce();
+ return s_data->mutex;
+ }
private:
+ static void coalesce()
+ {
+ if (s_data)
+ return;
+
+ const char* disambiguator = __PRETTY_FUNCTION__;
+ s_data = getPerProcessData(stringHash(disambiguator), disambiguator, sizeof(T), std::alignment_of<T>::value);
+ }
+
BNO_INLINE static T* getSlowCase()
{
- std::lock_guard<StaticMutex> lock(s_mutex);
- if (!s_object.load(std::memory_order_consume)) {
- T* t = new (&s_memory) T(lock);
- s_object.store(t, std::memory_order_release);
+ std::lock_guard<StaticMutex> lock(mutex());
+ if (!s_object.load()) {
+ if (s_data->isInitialized)
+ s_object.store(static_cast<T*>(s_data->memory));
+ else {
+ T* t = new (s_data->memory) T(lock);
+ s_object.store(t);
+ s_data->isInitialized = true;
+ }
}
- return s_object.load(std::memory_order_consume);
+ return s_object.load();
}
static std::atomic<T*> s_object;
- static StaticMutex s_mutex;
-
- typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type Memory;
- static Memory s_memory;
+ static PerProcessData* s_data;
};
template<typename T>
@@ -95,64 +127,6 @@
std::atomic<T*> PerProcess<T>::s_object;
template<typename T>
-StaticMutex PerProcess<T>::s_mutex;
+PerProcessData* PerProcess<T>::s_data;
-template<typename T>
-typename PerProcess<T>::Memory PerProcess<T>::s_memory;
-
-
-// SafePerProcess<T> behaves like PerProcess<T>, but its usage
-// requires DECLARE/DEFINE macros that export symbols that allow for
-// a single shared instance is across images in the process.
-
-template<typename T> struct SafePerProcessStorageTraits;
-
-template<typename T>
-class BEXPORT SafePerProcess {
-public:
- using Storage = typename SafePerProcessStorageTraits<T>::Storage;
-
- static T* get()
- {
- T* object = getFastCase();
- if (!object)
- return getSlowCase();
- return object;
- }
-
- static T* getFastCase()
- {
- return (Storage::s_object).load(std::memory_order_relaxed);
- }
-
- static StaticMutex& mutex() { return Storage::s_mutex; }
-
- using Memory = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
-
-private:
- BNO_INLINE static T* getSlowCase()
- {
- std::lock_guard<StaticMutex> lock(Storage::s_mutex);
- if (!Storage::s_object.load(std::memory_order_consume)) {
- T* t = new (&Storage::s_memory) T(lock);
- Storage::s_object.store(t, std::memory_order_release);
- }
- return Storage::s_object.load(std::memory_order_consume);
- }
-};
-
-#define DECLARE_SAFE_PER_PROCESS_STORAGE(Type) \
- template<> struct SafePerProcessStorageTraits<Type> { \
- struct BEXPORT Storage { \
- BEXPORT static std::atomic<Type*> s_object; \
- BEXPORT static StaticMutex s_mutex; \
- BEXPORT static SafePerProcess<Type>::Memory s_memory; \
- }; \
- };
-
-#define DEFINE_SAFE_PER_PROCESS_STORAGE(Type) \
- std::atomic<Type*> SafePerProcessStorageTraits<Type>::Storage::s_object; \
- StaticMutex SafePerProcessStorageTraits<Type>::Storage::s_mutex; \
- SafePerProcess<Type>::Memory SafePerProcessStorageTraits<Type>::Storage::s_memory;
-
} // namespace bmalloc
Modified: trunk/Source/bmalloc/bmalloc/Scavenger.cpp (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/Scavenger.cpp 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/Scavenger.cpp 2018-03-11 17:45:49 UTC (rev 229516)
@@ -32,8 +32,6 @@
namespace bmalloc {
-DEFINE_SAFE_PER_PROCESS_STORAGE(Scavenger);
-
Scavenger::Scavenger(std::lock_guard<StaticMutex>&)
{
#if BOS(DARWIN)
Modified: trunk/Source/bmalloc/bmalloc/Scavenger.h (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/Scavenger.h 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/Scavenger.h 2018-03-11 17:45:49 UTC (rev 229516)
@@ -93,8 +93,6 @@
Vector<DeferredDecommit> m_deferredDecommits;
};
-DECLARE_SAFE_PER_PROCESS_STORAGE(Scavenger);
-
} // namespace bmalloc
Modified: trunk/Source/bmalloc/bmalloc/bmalloc.cpp (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc/bmalloc.cpp 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc/bmalloc.cpp 2018-03-11 17:45:49 UTC (rev 229516)
@@ -73,7 +73,7 @@
{
scavengeThisThread();
- SafePerProcess<Scavenger>::get()->scavenge();
+ PerProcess<Scavenger>::get()->scavenge();
}
bool isEnabled(HeapKind kind)
@@ -87,7 +87,7 @@
void setScavengerThreadQOSClass(qos_class_t overrideClass)
{
std::unique_lock<StaticMutex> lock(Heap::mutex());
- SafePerProcess<Scavenger>::get()->setScavengerThreadQOSClass(overrideClass);
+ PerProcess<Scavenger>::get()->setScavengerThreadQOSClass(overrideClass);
}
#endif
Modified: trunk/Source/bmalloc/bmalloc.xcodeproj/project.pbxproj (229515 => 229516)
--- trunk/Source/bmalloc/bmalloc.xcodeproj/project.pbxproj 2018-03-11 08:03:30 UTC (rev 229515)
+++ trunk/Source/bmalloc/bmalloc.xcodeproj/project.pbxproj 2018-03-11 17:45:49 UTC (rev 229516)
@@ -21,6 +21,7 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 0F26A7A5205483130090A141 /* PerProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F26A7A42054830D0090A141 /* PerProcess.cpp */; };
0F5167741FAD685C008236A8 /* bmalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5167731FAD6852008236A8 /* bmalloc.cpp */; };
0F5549EF1FB54704007FF75A /* IsoPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5549EE1FB54701007FF75A /* IsoPage.cpp */; };
0F5BF1471F22A8B10029D91D /* HeapKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5BF1461F22A8B10029D91D /* HeapKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -174,6 +175,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 0F26A7A42054830D0090A141 /* PerProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PerProcess.cpp; path = bmalloc/PerProcess.cpp; sourceTree = "<group>"; };
0F5167731FAD6852008236A8 /* bmalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bmalloc.cpp; path = bmalloc/bmalloc.cpp; sourceTree = "<group>"; };
0F5549EE1FB54701007FF75A /* IsoPage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IsoPage.cpp; path = bmalloc/IsoPage.cpp; sourceTree = "<group>"; };
0F5BF1461F22A8B10029D91D /* HeapKind.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HeapKind.h; path = bmalloc/HeapKind.h; sourceTree = "<group>"; };
@@ -521,6 +523,7 @@
4426E27F1C838EE0008EB042 /* Logging.h */,
14C8992A1CC485E70027A057 /* Map.h */,
144DCED617A649D90093B2F2 /* Mutex.h */,
+ 0F26A7A42054830D0090A141 /* PerProcess.cpp */,
0F5BF1481F22A8D80029D91D /* PerHeapKind.h */,
14446A0717A61FA400F9EA1D /* PerProcess.h */,
144469FD17A61F1F00F9EA1D /* PerThread.h */,
@@ -768,6 +771,7 @@
14F271C318EA3978008C152F /* Allocator.cpp in Sources */,
6599C5CC1EC3F15900A2F7BB /* AvailableMemory.cpp in Sources */,
14F271C418EA397B008C152F /* Cache.cpp in Sources */,
+ 0F26A7A5205483130090A141 /* PerProcess.cpp in Sources */,
14F271C518EA397E008C152F /* Deallocator.cpp in Sources */,
142B44361E2839E7001DA6E9 /* DebugHeap.cpp in Sources */,
14895D911A3A319C0006235D /* Environment.cpp in Sources */,