summaryrefslogtreecommitdiff
path: root/Source/WTF/wtf
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
commit43a42f108af6bcbd91f2672731c3047c26213af1 (patch)
tree7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/WTF/wtf
parentd9cf437c840c6eb7417bdd97e6c40979255d3158 (diff)
downloadqtwebkit-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.h99
-rw-r--r--Source/WTF/wtf/MemoryInstrumentation.h45
-rw-r--r--Source/WTF/wtf/StackBounds.h21
-rw-r--r--Source/WTF/wtf/StackStats.cpp309
-rw-r--r--Source/WTF/wtf/StackStats.h151
-rw-r--r--Source/WTF/wtf/ThreadingPthreads.cpp2
-rw-r--r--Source/WTF/wtf/WTFThreadData.cpp3
-rw-r--r--Source/WTF/wtf/WTFThreadData.h11
-rw-r--r--Source/WTF/wtf/unicode/UTF8.cpp20
-rw-r--r--Source/WTF/wtf/unicode/UTF8.h2
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,