diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
commit | 43a42f108af6bcbd91f2672731c3047c26213af1 (patch) | |
tree | 7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/WTF/wtf | |
parent | d9cf437c840c6eb7417bdd97e6c40979255d3158 (diff) | |
download | qtwebkit-43a42f108af6bcbd91f2672731c3047c26213af1.tar.gz |
Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067)
New snapshot that fixes build without QtWidgets
Diffstat (limited to 'Source/WTF/wtf')
-rw-r--r-- | Source/WTF/wtf/Deque.h | 99 | ||||
-rw-r--r-- | Source/WTF/wtf/MemoryInstrumentation.h | 45 | ||||
-rw-r--r-- | Source/WTF/wtf/StackBounds.h | 21 | ||||
-rw-r--r-- | Source/WTF/wtf/StackStats.cpp | 309 | ||||
-rw-r--r-- | Source/WTF/wtf/StackStats.h | 151 | ||||
-rw-r--r-- | Source/WTF/wtf/ThreadingPthreads.cpp | 2 | ||||
-rw-r--r-- | Source/WTF/wtf/WTFThreadData.cpp | 3 | ||||
-rw-r--r-- | Source/WTF/wtf/WTFThreadData.h | 11 | ||||
-rw-r--r-- | Source/WTF/wtf/unicode/UTF8.cpp | 20 | ||||
-rw-r--r-- | Source/WTF/wtf/unicode/UTF8.h | 2 |
10 files changed, 564 insertions, 99 deletions
diff --git a/Source/WTF/wtf/Deque.h b/Source/WTF/wtf/Deque.h index be69c81db..e5c47b63e 100644 --- a/Source/WTF/wtf/Deque.h +++ b/Source/WTF/wtf/Deque.h @@ -33,6 +33,7 @@ // FIXME: Could move what Vector and Deque share into a separate file. // Deque doesn't actually use Vector. +#include <iterator> #include <wtf/PassTraits.h> #include <wtf/Vector.h> @@ -41,8 +42,6 @@ namespace WTF { template<typename T, size_t inlineCapacity> class DequeIteratorBase; template<typename T, size_t inlineCapacity> class DequeIterator; template<typename T, size_t inlineCapacity> class DequeConstIterator; - template<typename T, size_t inlineCapacity> class DequeReverseIterator; - template<typename T, size_t inlineCapacity> class DequeConstReverseIterator; template<typename T, size_t inlineCapacity = 0> class Deque { @@ -50,8 +49,8 @@ namespace WTF { public: typedef DequeIterator<T, inlineCapacity> iterator; typedef DequeConstIterator<T, inlineCapacity> const_iterator; - typedef DequeReverseIterator<T, inlineCapacity> reverse_iterator; - typedef DequeConstReverseIterator<T, inlineCapacity> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef PassTraits<T> Pass; typedef typename PassTraits<T>::PassType PassType; @@ -69,10 +68,10 @@ namespace WTF { iterator end() { return iterator(this, m_end); } const_iterator begin() const { return const_iterator(this, m_start); } const_iterator end() const { return const_iterator(this, m_end); } - reverse_iterator rbegin() { return reverse_iterator(this, m_end); } - reverse_iterator rend() { return reverse_iterator(this, m_start); } - const_reverse_iterator rbegin() const { return const_reverse_iterator(this, m_end); } - const_reverse_iterator rend() const { return const_reverse_iterator(this, m_start); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } T& first() { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; } const T& first() const { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; } @@ -117,17 +116,14 @@ namespace WTF { template<typename T, size_t inlineCapacity = 0> class DequeIteratorBase { - private: - typedef DequeIteratorBase<T, inlineCapacity> Base; - protected: DequeIteratorBase(); DequeIteratorBase(const Deque<T, inlineCapacity>*, size_t); - DequeIteratorBase(const Base&); - Base& operator=(const Base&); + DequeIteratorBase(const DequeIteratorBase&); + DequeIteratorBase& operator=(const DequeIteratorBase&); ~DequeIteratorBase(); - void assign(const Base& other) { *this = other; } + void assign(const DequeIteratorBase& other) { *this = other; } void increment(); void decrement(); @@ -135,13 +131,13 @@ namespace WTF { T* before() const; T* after() const; - bool isEqual(const Base&) const; + bool isEqual(const DequeIteratorBase&) const; private: void addToIteratorsList(); void removeFromIteratorsList(); void checkValidity() const; - void checkValidity(const Base&) const; + void checkValidity(const DequeIteratorBase&) const; Deque<T, inlineCapacity>* m_deque; size_t m_index; @@ -161,6 +157,12 @@ namespace WTF { typedef DequeIterator<T, inlineCapacity> Iterator; public: + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + DequeIterator(Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { } DequeIterator(const Iterator& other) : Base(other) { } @@ -186,6 +188,12 @@ namespace WTF { typedef DequeIterator<T, inlineCapacity> NonConstIterator; public: + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + DequeConstIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { } DequeConstIterator(const Iterator& other) : Base(other) { } @@ -205,57 +213,6 @@ namespace WTF { // postfix -- intentionally omitted }; - template<typename T, size_t inlineCapacity = 0> - class DequeReverseIterator : public DequeIteratorBase<T, inlineCapacity> { - private: - typedef DequeIteratorBase<T, inlineCapacity> Base; - typedef DequeReverseIterator<T, inlineCapacity> Iterator; - - public: - DequeReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { } - - DequeReverseIterator(const Iterator& other) : Base(other) { } - DequeReverseIterator& operator=(const Iterator& other) { Base::assign(other); return *this; } - - T& operator*() const { return *Base::before(); } - T* operator->() const { return Base::before(); } - - bool operator==(const Iterator& other) const { return Base::isEqual(other); } - bool operator!=(const Iterator& other) const { return !Base::isEqual(other); } - - Iterator& operator++() { Base::decrement(); return *this; } - // postfix ++ intentionally omitted - Iterator& operator--() { Base::increment(); return *this; } - // postfix -- intentionally omitted - }; - - template<typename T, size_t inlineCapacity = 0> - class DequeConstReverseIterator : public DequeIteratorBase<T, inlineCapacity> { - private: - typedef DequeIteratorBase<T, inlineCapacity> Base; - typedef DequeConstReverseIterator<T, inlineCapacity> Iterator; - typedef DequeReverseIterator<T, inlineCapacity> NonConstIterator; - - public: - DequeConstReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { } - - DequeConstReverseIterator(const Iterator& other) : Base(other) { } - DequeConstReverseIterator(const NonConstIterator& other) : Base(other) { } - DequeConstReverseIterator& operator=(const Iterator& other) { Base::assign(other); return *this; } - DequeConstReverseIterator& operator=(const NonConstIterator& other) { Base::assign(other); return *this; } - - const T& operator*() const { return *Base::before(); } - const T* operator->() const { return Base::before(); } - - bool operator==(const Iterator& other) const { return Base::isEqual(other); } - bool operator!=(const Iterator& other) const { return !Base::isEqual(other); } - - Iterator& operator++() { Base::decrement(); return *this; } - // postfix ++ intentionally omitted - Iterator& operator--() { Base::increment(); return *this; } - // postfix -- intentionally omitted - }; - #ifdef NDEBUG template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkValidity() const { } template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkIndexValidity(size_t) const { } @@ -540,7 +497,7 @@ namespace WTF { } template<typename T, size_t inlineCapacity> - void DequeIteratorBase<T, inlineCapacity>::checkValidity(const Base& other) const + void DequeIteratorBase<T, inlineCapacity>::checkValidity(const DequeIteratorBase& other) const { checkValidity(); other.checkValidity(); @@ -602,7 +559,7 @@ namespace WTF { } template<typename T, size_t inlineCapacity> - inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Base& other) + inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const DequeIteratorBase& other) : m_deque(other.m_deque) , m_index(other.m_index) { @@ -611,7 +568,7 @@ namespace WTF { } template<typename T, size_t inlineCapacity> - inline DequeIteratorBase<T, inlineCapacity>& DequeIteratorBase<T, inlineCapacity>::operator=(const Base& other) + inline DequeIteratorBase<T, inlineCapacity>& DequeIteratorBase<T, inlineCapacity>::operator=(const DequeIteratorBase& other) { other.checkValidity(); removeFromIteratorsList(); @@ -633,7 +590,7 @@ namespace WTF { } template<typename T, size_t inlineCapacity> - inline bool DequeIteratorBase<T, inlineCapacity>::isEqual(const Base& other) const + inline bool DequeIteratorBase<T, inlineCapacity>::isEqual(const DequeIteratorBase& other) const { checkValidity(other); return m_index == other.m_index; diff --git a/Source/WTF/wtf/MemoryInstrumentation.h b/Source/WTF/wtf/MemoryInstrumentation.h index 0b7c21731..7ea5cc65f 100644 --- a/Source/WTF/wtf/MemoryInstrumentation.h +++ b/Source/WTF/wtf/MemoryInstrumentation.h @@ -54,12 +54,14 @@ public: : m_memoryInstrumentation(memoryInstrumentation) , m_objectType(ownerObjectType) , m_objectSize(0) + , m_pointer(0) { } typedef MemoryClassInfo ClassInfo; MemoryObjectType objectType() const { return m_objectType; } size_t objectSize() const { return m_objectSize; } + const void* reportedPointer() const { return m_pointer; } MemoryInstrumentation* memoryInstrumentation() { return m_memoryInstrumentation; } @@ -67,10 +69,11 @@ private: friend class MemoryClassInfo; friend class MemoryInstrumentation; - template<typename T> void reportObjectInfo(MemoryObjectType objectType, size_t actualSize) + void reportObjectInfo(const void* pointer, MemoryObjectType objectType, size_t objectSize) { if (!m_objectSize) { - m_objectSize = actualSize ? actualSize : sizeof(T); + m_pointer = pointer; + m_objectSize = objectSize; if (objectType) m_objectType = objectType; } @@ -79,6 +82,7 @@ private: MemoryInstrumentation* m_memoryInstrumentation; MemoryObjectType m_objectType; size_t m_objectSize; + const void* m_pointer; }; template<typename T> void reportMemoryUsage(const T* const&, MemoryObjectInfo*); @@ -86,7 +90,7 @@ template<typename T> void reportMemoryUsage(const T* const&, MemoryObjectInfo*); class MemoryInstrumentationClient { public: virtual ~MemoryInstrumentationClient() { } - virtual void countObjectSize(MemoryObjectType, size_t) = 0; + virtual void countObjectSize(const void*, MemoryObjectType, size_t) = 0; virtual bool visited(const void*) = 0; virtual void checkCountedObject(const void*) = 0; }; @@ -110,7 +114,7 @@ protected: }; private: - void countObjectSize(MemoryObjectType objectType, size_t size) { m_client->countObjectSize(objectType, size); } + void countObjectSize(const void* object, MemoryObjectType objectType, size_t size) { m_client->countObjectSize(object, objectType, size); } bool visited(const void* pointer) { return m_client->visited(pointer); } void checkCountedObject(const void* pointer) { return m_client->checkCountedObject(pointer); } @@ -135,9 +139,9 @@ private: } template<typename T, typename Type> - static void reportObjectMemoryUsage(const T* const&, MemoryObjectInfo* memoryObjectInfo, ...) + static void reportObjectMemoryUsage(const T* const& object, MemoryObjectInfo* memoryObjectInfo, ...) { - memoryObjectInfo->reportObjectInfo<T>(0, sizeof(T)); + memoryObjectInfo->reportObjectInfo(object, 0, sizeof(T)); } template<typename T> @@ -159,7 +163,7 @@ private: { if (!buffer || visited(buffer)) return; - countObjectSize(ownerObjectType, size); + countObjectSize(buffer, ownerObjectType, size); } template<typename T> @@ -188,18 +192,18 @@ private: class MemoryClassInfo { public: template<typename T> - MemoryClassInfo(MemoryObjectInfo* memoryObjectInfo, const T*, MemoryObjectType objectType = 0, size_t actualSize = 0) + MemoryClassInfo(MemoryObjectInfo* memoryObjectInfo, const T* pointer, MemoryObjectType objectType = 0, size_t actualSize = 0) : m_memoryObjectInfo(memoryObjectInfo) , m_memoryInstrumentation(memoryObjectInfo->memoryInstrumentation()) { - m_memoryObjectInfo->reportObjectInfo<T>(objectType, actualSize); + m_memoryObjectInfo->reportObjectInfo(pointer, objectType, actualSize ? actualSize : sizeof(T)); m_objectType = memoryObjectInfo->objectType(); } template<typename M> void addMember(const M& member) { m_memoryInstrumentation->addObject(member, m_objectType); } template<typename ListHashSetType> void addListHashSet(const ListHashSetType& set) { m_memoryInstrumentation->addListHashSet(set, m_objectType, true); } void addRawBuffer(const void* const& buffer, size_t size) { m_memoryInstrumentation->addRawBuffer(buffer, m_objectType, size); } - void addPrivateBuffer(size_t size) { m_memoryInstrumentation->countObjectSize(m_objectType, size); } + void addPrivateBuffer(size_t size) { m_memoryInstrumentation->countObjectSize(0, m_objectType, size); } void addWeakPointer(void*) { } @@ -232,20 +236,16 @@ void MemoryInstrumentation::addObjectImpl(const T* const& object, MemoryObjectTy template<typename T> void MemoryInstrumentation::addObjectImpl(const OwnPtr<T>* const& object, MemoryObjectType ownerObjectType, MemoryOwningType owningType) { - if (owningType == byPointer && !visited(object)) { - countObjectSize(ownerObjectType, sizeof(*object)); - checkCountedObject(object); - } + if (owningType == byPointer && !visited(object)) + countObjectSize(object, ownerObjectType, sizeof(*object)); addObjectImpl(object->get(), ownerObjectType, byPointer); } template<typename T> void MemoryInstrumentation::addObjectImpl(const RefPtr<T>* const& object, MemoryObjectType ownerObjectType, MemoryOwningType owningType) { - if (owningType == byPointer && !visited(object)) { - countObjectSize(ownerObjectType, sizeof(*object)); - checkCountedObject(object); - } + if (owningType == byPointer && !visited(object)) + countObjectSize(object, ownerObjectType, sizeof(*object)); addObjectImpl(object->get(), ownerObjectType, byPointer); } @@ -255,7 +255,7 @@ void MemoryInstrumentation::addListHashSet(const ListHashSetType& hashSet, Memor if (visited(&hashSet)) return; size_t size = (contentOnly ? 0 : sizeof(ListHashSetType)) + hashSet.capacity() * sizeof(void*) + hashSet.size() * (sizeof(typename ListHashSetType::ValueType) + 2 * sizeof(void*)); - countObjectSize(ownerObjectType, size); + countObjectSize(&hashSet, ownerObjectType, size); } template<typename T> @@ -263,7 +263,12 @@ void MemoryInstrumentation::InstrumentedPointer<T>::process(MemoryInstrumentatio { MemoryObjectInfo memoryObjectInfo(memoryInstrumentation, m_ownerObjectType); reportMemoryUsage(m_pointer, &memoryObjectInfo); - memoryInstrumentation->countObjectSize(memoryObjectInfo.objectType(), memoryObjectInfo.objectSize()); + + const void* pointer = memoryObjectInfo.reportedPointer(); + ASSERT(pointer); + if (pointer != m_pointer && memoryInstrumentation->visited(pointer)) + return; + memoryInstrumentation->countObjectSize(pointer, memoryObjectInfo.objectType(), memoryObjectInfo.objectSize()); } // Link time guard for classes with external memory instrumentation. diff --git a/Source/WTF/wtf/StackBounds.h b/Source/WTF/wtf/StackBounds.h index afce8606f..185afec22 100644 --- a/Source/WTF/wtf/StackBounds.h +++ b/Source/WTF/wtf/StackBounds.h @@ -30,9 +30,15 @@ namespace WTF { class StackBounds { - // recursionCheck() / recursionLimit() tests (by default) + // isSafeToRecurse() / recursionLimit() tests (by default) // that we are at least this far from the end of the stack. - const static size_t s_defaultAvailabilityDelta = 4096; + // + // This 64k number was picked because a sampling of stack usage differences + // between consecutive entries into one of the Interpreter::execute...() + // functions was seen to be as high as 27k. Hence, 64k is chosen as a + // conservative availability value that is not too large but comfortably + // exceeds 27k with some buffer for error. + const static size_t s_defaultAvailabilityDelta = 64 * 1024; public: StackBounds() @@ -62,6 +68,13 @@ public: return currentPosition; } + size_t size() const + { + return isGrowingDownward() + ? static_cast<char*>(m_origin) - static_cast<char*>(m_bound) + : static_cast<char*>(m_bound) - static_cast<char*>(m_origin); + } + void* recursionLimit(size_t minAvailableDelta = s_defaultAvailabilityDelta) const { checkConsistency(); @@ -70,7 +83,7 @@ public: : static_cast<char*>(m_bound) - minAvailableDelta; } - bool recursionCheck(size_t minAvailableDelta = s_defaultAvailabilityDelta) const + bool isSafeToRecurse(size_t minAvailableDelta = s_defaultAvailabilityDelta) const { checkConsistency(); return isGrowingDownward() @@ -105,6 +118,8 @@ private: void* m_origin; void* m_bound; + + friend class StackStats; }; } // namespace WTF diff --git a/Source/WTF/wtf/StackStats.cpp b/Source/WTF/wtf/StackStats.cpp new file mode 100644 index 000000000..0bc11ed7b --- /dev/null +++ b/Source/WTF/wtf/StackStats.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2012 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 "config.h" +#include "StackStats.h" + +#if ENABLE(STACK_STATS) + +#include "Assertions.h" +#include "DataLog.h" +#include "WTFThreadData.h" + +// Define the following flag if you want to collect stats on every single +// checkpoint. By default, we only log checkpoints that establish new +// max values. + +// #define ENABLE_VERBOSE_STACK_STATS 1 + + +namespace WTF { + +// CheckPoint management: +Mutex* StackStats::s_sharedLock = 0; +StackStats::CheckPoint* StackStats::s_topCheckPoint = 0; +StackStats::LayoutCheckPoint* StackStats::s_firstLayoutCheckPoint = 0; +StackStats::LayoutCheckPoint* StackStats::s_topLayoutCheckPoint = 0; + +// High watermark stats: +int StackStats::s_maxCheckPointDiff = 0; +int StackStats::s_maxStackHeight = 0; +int StackStats::s_maxReentryDepth = 0; + +int StackStats::s_maxLayoutCheckPointDiff = 0; +int StackStats::s_maxTotalLayoutCheckPointDiff = 0; +int StackStats::s_maxLayoutReentryDepth = 0; + + +// Initializes locks and the log. Should only be called once. +void StackStats::initialize() +{ + s_sharedLock = new Mutex(); + dataLog(" === LOG new stack stats ========\n"); +} + +StackStats::PerThreadStats::PerThreadStats() +{ + const StackBounds& stack = wtfThreadData().stack(); + m_reentryDepth = 0; + m_stackStart = (char*)stack.origin(); + m_currentCheckPoint = 0; + + dataLog(" === THREAD new stackStart %p ========\n", m_stackStart); +} + +StackStats::CheckPoint::CheckPoint() +{ + MutexLocker locker(*StackStats::s_sharedLock); + WTFThreadData* threadData = const_cast<WTFThreadData*>(&wtfThreadData()); + StackStats::PerThreadStats& t = threadData->stackStats(); + const StackBounds& stack = threadData->stack(); + + bool isGrowingDownward = stack.isGrowingDownward(); + bool needToLog = false; + char* current = reinterpret_cast<char*>(this); + char* last = reinterpret_cast<char*>(t.m_currentCheckPoint); + + // If there was no previous checkpoint, measure from the start of the stack: + if (!last) + last = t.m_stackStart; + + // Update the reentry depth stats: + t.m_reentryDepth++; + if (t.m_reentryDepth > StackStats::s_maxReentryDepth) { + StackStats::s_maxReentryDepth = t.m_reentryDepth; + needToLog = true; + } + + // Update the stack height stats: + int height = t.m_stackStart - current; + if (!isGrowingDownward) + height = -height; + if (height > StackStats::s_maxStackHeight) { + StackStats::s_maxStackHeight = height; + needToLog = true; + } + + // Update the checkpoint diff stats: + int diff = last - current; + if (!isGrowingDownward) + diff = -diff; + if (diff > StackStats::s_maxCheckPointDiff) { + StackStats::s_maxCheckPointDiff = diff; + needToLog = true; + } + + // Push this checkpoint: + m_prev = t.m_currentCheckPoint; + t.m_currentCheckPoint = this; + +#if ENABLE(VERBOSE_STACK_STATS) + needToLog = true; // always log. +#endif + + // Log this checkpoint if needed: + if (needToLog) + dataLog(" CHECKPOINT %p diff %d/%.1fk/max %.1fk | reentry %d/max %d | height %.1fk/max %.1fk | stack %p size %.1fk\n", + this, diff, diff / 1024.0, StackStats::s_maxCheckPointDiff / 1024.0, + t.m_reentryDepth, StackStats::s_maxReentryDepth, + height / 1024.0, StackStats::s_maxStackHeight / 1024.0, + stack.origin(), stack.size() / 1024.0); +} + +StackStats::CheckPoint::~CheckPoint() +{ + MutexLocker locker(*StackStats::s_sharedLock); + WTFThreadData* threadData = const_cast<WTFThreadData*>(&wtfThreadData()); + StackStats::PerThreadStats& t = threadData->stackStats(); + + // Pop to previous checkpoint: + t.m_currentCheckPoint = m_prev; + --t.m_reentryDepth; + + // Log this checkpoint if needed: +#if ENABLE(VERBOSE_STACK_STATS) + if (!m_prev) { + const StackBounds& stack = threadData->stack(); + bool isGrowingDownward = stack.isGrowingDownward(); + + char* current = reinterpret_cast<char*>(this); + int height = t.m_stackStart - current; + + if (!isGrowingDownward) + height = -height; + + dataLog(" POP to %p diff max %.1fk | reentry %d/%d max | height %.1fk/max %.1fk | stack %p size %.1fk)\n", + this, StackStats::s_maxCheckPointDiff / 1024.0, + t.m_reentryDepth, StackStats::s_maxReentryDepth, + height / 1024.0, StackStats::s_maxStackHeight / 1024.0, + stack.origin(), stack.size() / 1024.0); + } +#endif +} + +void StackStats::probe() +{ + MutexLocker locker(*StackStats::s_sharedLock); + WTFThreadData* threadData = const_cast<WTFThreadData*>(&wtfThreadData()); + StackStats::PerThreadStats& t = threadData->stackStats(); + const StackBounds& stack = threadData->stack(); + + bool isGrowingDownward = stack.isGrowingDownward(); + + bool needToLog = false; + + int dummy; + char* current = reinterpret_cast<char*>(&dummy); + char* last = reinterpret_cast<char*>(t.m_currentCheckPoint); + + // If there was no previous checkpoint, measure from the start of the stack: + if (!last) + last = t.m_stackStart; + + // We did not reach another checkpoint yet. Hence, we do not touch the + // reentry stats. + + // Update the stack height stats: + int height = t.m_stackStart - current; + if (!isGrowingDownward) + height = -height; + if (height > StackStats::s_maxStackHeight) { + StackStats::s_maxStackHeight = height; + needToLog = true; + } + + // Update the checkpoint diff stats: + int diff = last - current; + if (!isGrowingDownward) + diff = -diff; + if (diff > StackStats::s_maxCheckPointDiff) { + StackStats::s_maxCheckPointDiff = diff; + needToLog = true; + } + +#if ENABLE(VERBOSE_STACK_STATS) + needToLog = true; // always log. +#endif + + if (needToLog) + dataLog(" PROBE %p diff %d/%.1fk/max %.1fk | reentry %d/max %d | height %.1fk/max %.1fk | stack %p size %.1fk\n", + current, diff, diff / 1024.0, StackStats::s_maxCheckPointDiff / 1024.0, + t.m_reentryDepth, StackStats::s_maxReentryDepth, + height / 1024.0, StackStats::s_maxStackHeight / 1024.0, + stack.origin(), stack.size() / 1024.0); +} + +StackStats::LayoutCheckPoint::LayoutCheckPoint() +{ + // While a layout checkpoint is not necessarily a checkpoint where we + // we will do a recursion check, it is a convenient spot for doing a + // probe to measure the height of stack usage. + // + // We'll do this probe before we commence with the layout checkpoint. + // This is because the probe also locks the sharedLock. By calling the + // probe first, we can avoid re-entering the lock. + StackStats::probe(); + + MutexLocker locker(*StackStats::s_sharedLock); + WTFThreadData* threadData = const_cast<WTFThreadData*>(&wtfThreadData()); + StackStats::PerThreadStats& t = threadData->stackStats(); + const StackBounds& stack = threadData->stack(); + + bool isGrowingDownward = stack.isGrowingDownward(); + + // Push this checkpoint: + m_prev = StackStats::s_topLayoutCheckPoint; + if (m_prev) + m_depth = m_prev->m_depth + 1; + else { + StackStats::s_firstLayoutCheckPoint = this; + m_depth = 0; + } + StackStats::s_topLayoutCheckPoint = this; + + // + char* current = reinterpret_cast<char*>(this); + char* last = reinterpret_cast<char*>(m_prev); + char* root = reinterpret_cast<char*>(StackStats::s_firstLayoutCheckPoint); + bool needToLog = false; + + int diff = last - current; + if (!last) + diff = 0; + int totalDiff = root - current; + if (!root) + totalDiff = 0; + + // Update the stack height stats: + int height = t.m_stackStart - current; + if (!isGrowingDownward) + height = -height; + if (height > StackStats::s_maxStackHeight) { + StackStats::s_maxStackHeight = height; + needToLog = true; + } + + // Update the layout checkpoint diff stats: + if (!isGrowingDownward) + diff = -diff; + if (diff > StackStats::s_maxLayoutCheckPointDiff) { + StackStats::s_maxLayoutCheckPointDiff = diff; + needToLog = true; + } + + // Update the total layout checkpoint diff stats: + if (!isGrowingDownward) + totalDiff = -totalDiff; + if (totalDiff > StackStats::s_maxTotalLayoutCheckPointDiff) { + StackStats::s_maxTotalLayoutCheckPointDiff = totalDiff; + needToLog = true; + } + +#if ENABLE(VERBOSE_STACK_STATS) + needToLog = true; // always log. +#endif + + if (needToLog) + dataLog(" LAYOUT %p diff %d/%.1fk/max %.1fk | reentry %d/max %d | height %.1fk/max %.1fk | stack %p size %.1fk\n", + current, diff, diff / 1024.0, StackStats::s_maxLayoutCheckPointDiff / 1024.0, + m_depth, StackStats::s_maxLayoutReentryDepth, + totalDiff / 1024.0, StackStats::s_maxTotalLayoutCheckPointDiff / 1024.0, + stack.origin(), stack.size() / 1024.0); +} + +StackStats::LayoutCheckPoint::~LayoutCheckPoint() +{ + MutexLocker locker(*StackStats::s_sharedLock); + + // Pop to the previous layout checkpoint: + StackStats::s_topLayoutCheckPoint = m_prev; + if (!m_depth) + StackStats::s_firstLayoutCheckPoint = 0; +} + +} // namespace WTF + +#endif // ENABLE(STACK_STATS) + diff --git a/Source/WTF/wtf/StackStats.h b/Source/WTF/wtf/StackStats.h new file mode 100644 index 000000000..263567974 --- /dev/null +++ b/Source/WTF/wtf/StackStats.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef StackStats_h +#define StackStats_h + +#include "ExportMacros.h" +#include "ThreadingPrimitives.h" + + +// Define this flag to enable Stack stats collection. This feature is useful +// for getting a sample of native stack usage sizes. +// +// Enabling this will cause stats to be collected and written to a log file at +// various instrumented points in the code. It will result in noticeable +// performance loss. Hence, this should only be enable when you want to do +// some stats location in your local build. This code is provided here as a +// convenience for collecting that data. It is not meant to be enabled by +// default on release or debug builds. + +// #define ENABLE_STACK_STATS 1 + + +namespace WTF { + +#if !ENABLE(STACK_STATS) + +class StackStats { +public: + // The CheckPoint class is for marking check points corresponding + // each location in code where a stack recursion check is being done. + + class CheckPoint { + public: + CheckPoint() { } + }; + + class PerThreadStats { + public: + PerThreadStats() { } + }; + + class LayoutCheckPoint { + public: + LayoutCheckPoint() { } + }; + + static void initialize() { } + static void probe() { } +}; + +#else // ENABLE(STACK_STATS) + +class StackStats { +public: + // The CheckPoint class is for marking check points corresponding + // each location in code where a stack recursion check is being done. + + class CheckPoint { + public: + CheckPoint(); + ~CheckPoint(); + private: + CheckPoint* m_prev; + }; + + class PerThreadStats { + public: + PerThreadStats(); + + private: + int m_reentryDepth; + char* m_stackStart; + CheckPoint* m_currentCheckPoint; + + friend class CheckPoint; + friend class StackStats; + }; + + class LayoutCheckPoint { + public: + WTF_EXPORT_PRIVATE LayoutCheckPoint(); + WTF_EXPORT_PRIVATE ~LayoutCheckPoint(); + + private: + LayoutCheckPoint* m_prev; + int m_depth; + }; + + // Initializes locks and the log file. Should only be called once. + static void initialize(); + + // Used for probing the stack at places where we suspect to be high + // points of stack usage but are NOT check points where stack recursion + // is checked. + // + // The more places where we add this probe, the more accurate our + // stats data will be. However, adding too many probes will also + // result in unnecessary performance loss. So, only add these probes + // judiciously where appropriate. + static void probe(); + +private: + // CheckPoint management: + static Mutex* s_sharedLock; + static CheckPoint* s_topCheckPoint; + static LayoutCheckPoint* s_firstLayoutCheckPoint; + static LayoutCheckPoint* s_topLayoutCheckPoint; + + // High watermark stats: + static int s_maxCheckPointDiff; + static int s_maxStackHeight; + static int s_maxReentryDepth; + + static int s_maxLayoutCheckPointDiff; + static int s_maxTotalLayoutCheckPointDiff; + static int s_maxLayoutReentryDepth; + + friend class CheckPoint; + friend class LayoutCheckPoint; +}; + +#endif // ENABLE(STACK_STATS) + +} // namespace WTF + +using WTF::StackStats; + +#endif // StackStats_h diff --git a/Source/WTF/wtf/ThreadingPthreads.cpp b/Source/WTF/wtf/ThreadingPthreads.cpp index b70ccdd9a..1dd84f0ed 100644 --- a/Source/WTF/wtf/ThreadingPthreads.cpp +++ b/Source/WTF/wtf/ThreadingPthreads.cpp @@ -39,6 +39,7 @@ #include "dtoa/cached-powers.h" #include "HashMap.h" #include "RandomNumberSeed.h" +#include "StackStats.h" #include "StdLibExtras.h" #include "ThreadFunctionInvocation.h" #include "ThreadIdentifierDataPthreads.h" @@ -138,6 +139,7 @@ void initializeThreading() threadMapMutex(); initializeRandomNumberGenerator(); ThreadIdentifierData::initializeOnce(); + StackStats::initialize(); wtfThreadData(); s_dtoaP5Mutex = new Mutex; initializeDates(); diff --git a/Source/WTF/wtf/WTFThreadData.cpp b/Source/WTF/wtf/WTFThreadData.cpp index 3a903f895..7d9074844 100644 --- a/Source/WTF/wtf/WTFThreadData.cpp +++ b/Source/WTF/wtf/WTFThreadData.cpp @@ -38,7 +38,10 @@ WTFThreadData::WTFThreadData() , m_defaultIdentifierTable(new JSC::IdentifierTable()) , m_currentIdentifierTable(m_defaultIdentifierTable) , m_stackBounds(StackBounds::currentThreadStackBounds()) +#if ENABLE(STACK_STATS) + , m_stackStats() #endif +#endif // USE(JSC) { } diff --git a/Source/WTF/wtf/WTFThreadData.h b/Source/WTF/wtf/WTFThreadData.h index dbc5ba6ac..9c2a5db41 100644 --- a/Source/WTF/wtf/WTFThreadData.h +++ b/Source/WTF/wtf/WTFThreadData.h @@ -31,6 +31,7 @@ #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> #include <wtf/StackBounds.h> +#include <wtf/StackStats.h> #include <wtf/text/StringHash.h> #include <wtf/ThreadSpecific.h> #include <wtf/Threading.h> @@ -108,7 +109,14 @@ public: { return m_stackBounds; } + +#if ENABLE(STACK_STATS) + StackStats::PerThreadStats& stackStats() + { + return m_stackStats; + } #endif +#endif // USE(JSC) private: AtomicStringTable* m_atomicStringTable; @@ -118,7 +126,10 @@ private: JSC::IdentifierTable* m_defaultIdentifierTable; JSC::IdentifierTable* m_currentIdentifierTable; StackBounds m_stackBounds; +#if ENABLE(STACK_STATS) + StackStats::PerThreadStats m_stackStats; #endif +#endif // USE(JSC) static WTF_EXPORTDATA ThreadSpecific<WTFThreadData>* staticData; friend WTFThreadData& wtfThreadData(); diff --git a/Source/WTF/wtf/unicode/UTF8.cpp b/Source/WTF/wtf/unicode/UTF8.cpp index 6bec4051b..cb3039a53 100644 --- a/Source/WTF/wtf/unicode/UTF8.cpp +++ b/Source/WTF/wtf/unicode/UTF8.cpp @@ -297,11 +297,12 @@ static inline UChar32 readUTF8Sequence(const char*& sequence, unsigned length) ConversionResult convertUTF8ToUTF16( const char** sourceStart, const char* sourceEnd, - UChar** targetStart, UChar* targetEnd, bool strict) + UChar** targetStart, UChar* targetEnd, bool* sourceAllASCII, bool strict) { ConversionResult result = conversionOK; const char* source = *sourceStart; UChar* target = *targetStart; + UChar orAllData = 0; while (source < sourceEnd) { int utf8SequenceLength = inlineUTF8SequenceLength(*source); if (sourceEnd - source < utf8SequenceLength) { @@ -329,10 +330,14 @@ ConversionResult convertUTF8ToUTF16( source -= utf8SequenceLength; // return to the illegal value itself result = sourceIllegal; break; - } else + } else { *target++ = replacementCharacter; - } else + orAllData |= replacementCharacter; + } + } else { *target++ = character; // normal case + orAllData |= character; + } } else if (U_IS_SUPPLEMENTARY(character)) { // target is a character in range 0xFFFF - 0x10FFFF if (target + 1 >= targetEnd) { @@ -342,17 +347,24 @@ ConversionResult convertUTF8ToUTF16( } *target++ = U16_LEAD(character); *target++ = U16_TRAIL(character); + orAllData = 0xffff; } else { if (strict) { source -= utf8SequenceLength; // return to the start result = sourceIllegal; break; // Bail out; shouldn't continue - } else + } else { *target++ = replacementCharacter; + orAllData |= replacementCharacter; + } } } *sourceStart = source; *targetStart = target; + + if (sourceAllASCII) + *sourceAllASCII = !(orAllData & 0x7f); + return result; } diff --git a/Source/WTF/wtf/unicode/UTF8.h b/Source/WTF/wtf/unicode/UTF8.h index 33497daf6..1fc21baad 100644 --- a/Source/WTF/wtf/unicode/UTF8.h +++ b/Source/WTF/wtf/unicode/UTF8.h @@ -64,7 +64,7 @@ namespace Unicode { WTF_EXPORT_PRIVATE ConversionResult convertUTF8ToUTF16( const char** sourceStart, const char* sourceEnd, - UChar** targetStart, UChar* targetEnd, bool strict = true); + UChar** targetStart, UChar* targetEnd, bool* isSourceAllASCII = 0, bool strict = true); WTF_EXPORT_PRIVATE ConversionResult convertLatin1ToUTF8( const LChar** sourceStart, const LChar* sourceEnd, |