diff options
author | Feng Qian <> | 2009-04-10 18:11:29 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-10 18:11:29 -0700 |
commit | 8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch) | |
tree | 181bf9a400c30a1bf34ea6d72560e8d00111d549 /JavaScriptCore/wtf | |
parent | 7ed56f225e0ade046e1c2178977f72b2d896f196 (diff) | |
download | external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2 |
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'JavaScriptCore/wtf')
41 files changed, 1225 insertions, 371 deletions
diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index c17e501..9643517 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -194,7 +194,7 @@ while (0) /* COMPILE_ASSERT */ #ifndef COMPILE_ASSERT -#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]; +#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1] #endif /* FATAL */ diff --git a/JavaScriptCore/wtf/ByteArray.h b/JavaScriptCore/wtf/ByteArray.h index 865c30e..33f0877 100644 --- a/JavaScriptCore/wtf/ByteArray.h +++ b/JavaScriptCore/wtf/ByteArray.h @@ -69,8 +69,7 @@ namespace WTF { private: ByteArray(size_t size) - : RefCountedBase(1) - , m_size(size) + : m_size(size) { } size_t m_size; diff --git a/JavaScriptCore/wtf/CrossThreadRefCounted.h b/JavaScriptCore/wtf/CrossThreadRefCounted.h new file mode 100644 index 0000000..82f1ba1 --- /dev/null +++ b/JavaScriptCore/wtf/CrossThreadRefCounted.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 CrossThreadRefCounted_h +#define CrossThreadRefCounted_h + +#include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Threading.h> +#include <wtf/TypeTraits.h> + +namespace WTF { + + // Used to allowing sharing data across classes and threads (like ThreadedSafeShared). + // + // Why not just use ThreadSafeShared? + // ThreadSafeShared can have a significant perf impact when used in low level classes + // (like UString) that get ref/deref'ed a lot. This class has the benefit of doing fast ref + // counts like RefPtr whenever possible, but it has the downside that you need to copy it + // to use it on another thread. + // + // Is this class threadsafe? + // While each instance of the class is not threadsafe, the copied instance is threadsafe + // with respect to the original and any other copies. The underlying m_data is jointly + // owned by the original instance and all copies. + template<class T> + class CrossThreadRefCounted : Noncopyable { + public: + static PassRefPtr<CrossThreadRefCounted<T> > create(T* data) + { + return adoptRef(new CrossThreadRefCounted<T>(data, 0)); + } + + // Used to make an instance that can be used on another thread. + PassRefPtr<CrossThreadRefCounted<T> > crossThreadCopy(); + + void ref(); + void deref(); + T* release(); + +#ifndef NDEBUG + bool mayBePassedToAnotherThread() const { ASSERT(!m_threadId); return m_refCounter.hasOneRef(); } +#endif + + private: + CrossThreadRefCounted(T* data, ThreadSafeSharedBase* threadedCounter) + : m_threadSafeRefCounter(threadedCounter) + , m_data(data) +#ifndef NDEBUG + , m_threadId(0) +#endif + { + } + + ~CrossThreadRefCounted() + { + if (!m_threadSafeRefCounter) + delete m_data; + } + + void threadSafeDeref(); + + RefCountedBase m_refCounter; + ThreadSafeSharedBase* m_threadSafeRefCounter; + T* m_data; +#ifndef NDEBUG + ThreadIdentifier m_threadId; +#endif + }; + + template<class T> + void CrossThreadRefCounted<T>::ref() + { + ASSERT(!m_threadId || m_threadId == currentThread()); + m_refCounter.ref(); +#ifndef NDEBUG + // Store the threadId as soon as the ref count gets to 2. + // The class gets created with a ref count of 1 and then passed + // to another thread where to ref count get increased. This + // is a heuristic but it seems to always work and has helped + // find some bugs. + if (!m_threadId && m_refCounter.refCount() == 2) + m_threadId = currentThread(); +#endif + } + + template<class T> + void CrossThreadRefCounted<T>::deref() + { + ASSERT(!m_threadId || m_threadId == currentThread()); + if (m_refCounter.derefBase()) { + threadSafeDeref(); + delete this; + } else { +#ifndef NDEBUG + // Clear the threadId when the ref goes to 1 because it + // is safe to be passed to another thread at this point. + if (m_threadId && m_refCounter.refCount() == 1) + m_threadId = 0; +#endif + } + } + + template<class T> + T* CrossThreadRefCounted<T>::release() + { + ASSERT(!isShared()); + + T* data = m_data; + m_data = 0; + return data; + } + + template<class T> + PassRefPtr<CrossThreadRefCounted<T> > CrossThreadRefCounted<T>::crossThreadCopy() + { + if (m_threadSafeRefCounter) + m_threadSafeRefCounter->ref(); + else + m_threadSafeRefCounter = new ThreadSafeSharedBase(2); + return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter)); + } + + + template<class T> + void CrossThreadRefCounted<T>::threadSafeDeref() + { + if (m_threadSafeRefCounter && m_threadSafeRefCounter->derefBase()) { + delete m_threadSafeRefCounter; + m_threadSafeRefCounter = 0; + } + } +} // namespace WTF + +using WTF::CrossThreadRefCounted; + +#endif // CrossThreadRefCounted_h diff --git a/JavaScriptCore/wtf/CurrentTime.cpp b/JavaScriptCore/wtf/CurrentTime.cpp index d9ea448..74984c1 100644 --- a/JavaScriptCore/wtf/CurrentTime.cpp +++ b/JavaScriptCore/wtf/CurrentTime.cpp @@ -32,13 +32,9 @@ #include "config.h" #include "CurrentTime.h" -#if PLATFORM(MAC) -#include <CoreFoundation/CFDate.h> -#elif PLATFORM(GTK) -#include <glib.h> -#elif PLATFORM(WX) -#include <wx/datetime.h> -#elif PLATFORM(WIN_OS) +#if PLATFORM(WIN_OS) +// Windows is first since we want to use hires timers, despite PLATFORM(CF) +// being defined. // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. #undef WIN32_LEAN_AND_MEAN #include <windows.h> @@ -47,6 +43,12 @@ #include <sys/timeb.h> #include <sys/types.h> #include <time.h> +#elif PLATFORM(CF) +#include <CoreFoundation/CFDate.h> +#elif PLATFORM(GTK) +#include <glib.h> +#elif PLATFORM(WX) +#include <wx/datetime.h> #else // Posix systems relying on the gettimeofday() #include <sys/time.h> #endif @@ -55,35 +57,7 @@ namespace WTF { const double msPerSecond = 1000.0; -#if PLATFORM(MAC) - -double currentTime() -{ - return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; -} - -#elif PLATFORM(GTK) - -// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides -// better accuracy compared with Windows implementation of g_get_current_time: -// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). -// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. -double currentTime() -{ - GTimeVal now; - g_get_current_time(&now); - return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); -} - -#elif PLATFORM(WX) - -double currentTime() -{ - wxDateTime now = wxDateTime::UNow(); - return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); -} - -#elif PLATFORM(WIN_OS) +#if PLATFORM(WIN_OS) static LARGE_INTEGER qpcFrequency; static bool syncedTime; @@ -210,6 +184,34 @@ double currentTime() return utc / 1000.0; } +#elif PLATFORM(CF) + +double currentTime() +{ + return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; +} + +#elif PLATFORM(GTK) + +// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides +// better accuracy compared with Windows implementation of g_get_current_time: +// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). +// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. +double currentTime() +{ + GTimeVal now; + g_get_current_time(&now); + return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); +} + +#elif PLATFORM(WX) + +double currentTime() +{ + wxDateTime now = wxDateTime::UNow(); + return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); +} + #else // Other Posix systems rely on the gettimeofday(). double currentTime() diff --git a/JavaScriptCore/wtf/Deque.h b/JavaScriptCore/wtf/Deque.h index 70c546b..c371d38 100644 --- a/JavaScriptCore/wtf/Deque.h +++ b/JavaScriptCore/wtf/Deque.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -75,9 +76,14 @@ namespace WTF { template<typename U> void append(const U&); template<typename U> void prepend(const U&); void removeFirst(); + void remove(iterator&); + void remove(const_iterator&); void clear(); + template<typename Predicate> + iterator findIf(Predicate&); + private: friend class DequeIteratorBase<T>; @@ -85,6 +91,7 @@ namespace WTF { typedef VectorTypeOperations<T> TypeOperations; typedef DequeIteratorBase<T> IteratorBase; + void remove(size_t position); void invalidateIterators(); void destroyAll(); void checkValidity() const; @@ -124,6 +131,7 @@ namespace WTF { private: void addToIteratorsList(); + void removeFromIteratorsList(); void checkValidity() const; void checkValidity(const Base&) const; @@ -348,7 +356,7 @@ namespace WTF { destroyAll(); } - template <typename T> + template<typename T> inline void Deque<T>::swap(Deque<T>& other) { checkValidity(); @@ -361,7 +369,7 @@ namespace WTF { other.checkValidity(); } - template <typename T> + template<typename T> inline void Deque<T>::clear() { checkValidity(); @@ -373,6 +381,18 @@ namespace WTF { } template<typename T> + template<typename Predicate> + inline DequeIterator<T> Deque<T>::findIf(Predicate& predicate) + { + iterator end_iterator = end(); + for (iterator it = begin(); it != end_iterator; ++it) { + if (predicate(*it)) + return it; + } + return end_iterator; + } + + template<typename T> inline void Deque<T>::expandCapacityIfNeeded() { if (m_start) { @@ -447,10 +467,48 @@ namespace WTF { checkValidity(); } + template<typename T> + inline void Deque<T>::remove(iterator& it) + { + it.checkValidity(); + remove(it.m_index); + } + + template<typename T> + inline void Deque<T>::remove(const_iterator& it) + { + it.checkValidity(); + remove(it.m_index); + } + + template<typename T> + inline void Deque<T>::remove(size_t position) + { + if (position == m_end) + return; + + checkValidity(); + invalidateIterators(); + + T* buffer = m_buffer.buffer(); + TypeOperations::destruct(&buffer[position], &buffer[position + 1]); + + // Find which segment of the circular buffer contained the remove element, and only move elements in that part. + if (position >= m_start) { + TypeOperations::moveOverlapping(buffer + m_start, buffer + position, buffer + m_start + 1); + m_start = (m_start + 1) % m_buffer.capacity(); + } else { + TypeOperations::moveOverlapping(buffer + position + 1, buffer + m_end, buffer + position); + m_end = (m_end - 1 + m_buffer.capacity()) % m_buffer.capacity(); + } + checkValidity(); + } + #ifdef NDEBUG template<typename T> inline void DequeIteratorBase<T>::checkValidity() const { } template<typename T> inline void DequeIteratorBase<T>::checkValidity(const DequeIteratorBase<T>&) const { } template<typename T> inline void DequeIteratorBase<T>::addToIteratorsList() { } + template<typename T> inline void DequeIteratorBase<T>::removeFromIteratorsList() { } #else template<typename T> void DequeIteratorBase<T>::checkValidity() const @@ -480,6 +538,30 @@ namespace WTF { } m_previous = 0; } + + template<typename T> + void DequeIteratorBase<T>::removeFromIteratorsList() + { + if (!m_deque) { + ASSERT(!m_next); + ASSERT(!m_previous); + } else { + if (m_next) { + ASSERT(m_next->m_previous == this); + m_next->m_previous = m_previous; + } + if (m_previous) { + ASSERT(m_deque->m_iterators != this); + ASSERT(m_previous->m_next == this); + m_previous->m_next = m_next; + } else { + ASSERT(m_deque->m_iterators == this); + m_deque->m_iterators = m_next; + } + } + m_next = 0; + m_previous = 0; + } #endif template<typename T> @@ -507,30 +589,25 @@ namespace WTF { } template<typename T> + inline DequeIteratorBase<T>& DequeIteratorBase<T>::operator=(const Base& other) + { + checkValidity(); + other.checkValidity(); + removeFromIteratorsList(); + + m_deque = other.m_deque; + m_index = other.m_index; + addToIteratorsList(); + checkValidity(); + return *this; + } + + template<typename T> inline DequeIteratorBase<T>::~DequeIteratorBase() { #ifndef NDEBUG - // Delete iterator from doubly-linked list of iterators. - if (!m_deque) { - ASSERT(!m_next); - ASSERT(!m_previous); - } else { - if (m_next) { - ASSERT(m_next->m_previous == this); - m_next->m_previous = m_previous; - } - if (m_previous) { - ASSERT(m_deque->m_iterators != this); - ASSERT(m_previous->m_next == this); - m_previous->m_next = m_next; - } else { - ASSERT(m_deque->m_iterators == this); - m_deque->m_iterators = m_next; - } - } + removeFromIteratorsList(); m_deque = 0; - m_next = 0; - m_previous = 0; #endif } diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 88c10ca..bcac242 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -94,7 +94,7 @@ #define FORCE_SYSTEM_MALLOC 1 #endif -#define TCMALLOC_TRACK_DECOMMITED_SPANS (HAVE(VIRTUALALLOC)) +#define TCMALLOC_TRACK_DECOMMITED_SPANS (HAVE(VIRTUALALLOC) || HAVE(MADV_FREE_REUSE)) #ifndef NDEBUG namespace WTF { @@ -321,9 +321,11 @@ namespace WTF { #define CHECK_CONDITION ASSERT #if PLATFORM(DARWIN) +class Span; +class TCMalloc_Central_FreeListPadded; class TCMalloc_PageHeap; class TCMalloc_ThreadCache; -class TCMalloc_Central_FreeListPadded; +template <typename T> class PageHeapAllocator; class FastMallocZone { public: @@ -339,7 +341,7 @@ public: static void statistics(malloc_zone_t*, malloc_statistics_t* stats) { memset(stats, 0, sizeof(malloc_statistics_t)); } private: - FastMallocZone(TCMalloc_PageHeap*, TCMalloc_ThreadCache**, TCMalloc_Central_FreeListPadded*); + FastMallocZone(TCMalloc_PageHeap*, TCMalloc_ThreadCache**, TCMalloc_Central_FreeListPadded*, PageHeapAllocator<Span>*, PageHeapAllocator<TCMalloc_ThreadCache>*); static size_t size(malloc_zone_t*, const void*); static void* zoneMalloc(malloc_zone_t*, size_t); static void* zoneCalloc(malloc_zone_t*, size_t numItems, size_t size); @@ -352,6 +354,8 @@ private: TCMalloc_PageHeap* m_pageHeap; TCMalloc_ThreadCache** m_threadHeaps; TCMalloc_Central_FreeListPadded* m_centralCaches; + PageHeapAllocator<Span>* m_spanAllocator; + PageHeapAllocator<TCMalloc_ThreadCache>* m_pageHeapAllocator; }; #endif @@ -820,6 +824,9 @@ class PageHeapAllocator { char* free_area_; size_t free_avail_; + // Linked list of all regions allocated by this allocator + void* allocated_regions_; + // Free list of already carved objects void* free_list_; @@ -830,6 +837,7 @@ class PageHeapAllocator { void Init() { ASSERT(kAlignedSize <= kAllocIncrement); inuse_ = 0; + allocated_regions_ = 0; free_area_ = NULL; free_avail_ = 0; free_list_ = NULL; @@ -844,9 +852,14 @@ class PageHeapAllocator { } else { if (free_avail_ < kAlignedSize) { // Need more room - free_area_ = reinterpret_cast<char*>(MetaDataAlloc(kAllocIncrement)); - if (free_area_ == NULL) CRASH(); - free_avail_ = kAllocIncrement; + char* new_allocation = reinterpret_cast<char*>(MetaDataAlloc(kAllocIncrement)); + if (!new_allocation) + CRASH(); + + *(void**)new_allocation = allocated_regions_; + allocated_regions_ = new_allocation; + free_area_ = new_allocation + kAlignedSize; + free_avail_ = kAllocIncrement - kAlignedSize; } result = free_area_; free_area_ += kAlignedSize; @@ -863,6 +876,18 @@ class PageHeapAllocator { } int inuse() const { return inuse_; } + +#if defined(WTF_CHANGES) && PLATFORM(DARWIN) + template <class Recorder> + void recordAdministrativeRegions(Recorder& recorder, const RemoteMemoryReader& reader) + { + vm_address_t adminAllocation = reinterpret_cast<vm_address_t>(allocated_regions_); + while (adminAllocation) { + recorder.recordRegion(adminAllocation, kAllocIncrement); + adminAllocation = *reader(reinterpret_cast<vm_address_t*>(adminAllocation)); + } + } +#endif }; // ------------------------------------------------------------------------- @@ -1378,8 +1403,14 @@ static ALWAYS_INLINE void mergeDecommittedStates(Span*, Span*) { } #else static ALWAYS_INLINE void mergeDecommittedStates(Span* destination, Span* other) { - if (other->decommitted) + if (destination->decommitted && !other->decommitted) { + TCMalloc_SystemRelease(reinterpret_cast<void*>(other->start << kPageShift), + static_cast<size_t>(other->length << kPageShift)); + } else if (other->decommitted && !destination->decommitted) { + TCMalloc_SystemRelease(reinterpret_cast<void*>(destination->start << kPageShift), + static_cast<size_t>(destination->length << kPageShift)); destination->decommitted = true; + } } #endif @@ -3571,7 +3602,7 @@ extern "C" struct mallinfo mallinfo(void) { #if defined(__GLIBC__) extern "C" { -# if defined(__GNUC__) && !defined(__MACH__) && defined(HAVE___ATTRIBUTE__) +#if COMPILER(GCC) && !defined(__MACH__) && defined(HAVE___ATTRIBUTE__) // Potentially faster variants that use the gcc alias extension. // Mach-O (Darwin) does not support weak aliases, hence the __MACH__ check. # define ALIAS(x) __attribute__ ((weak, alias (x))) @@ -3630,6 +3661,7 @@ public: void visit(void* ptr) { m_freeObjects.add(ptr); } bool isFreeObject(void* ptr) const { return m_freeObjects.contains(ptr); } + bool isFreeObject(vm_address_t ptr) const { return isFreeObject(reinterpret_cast<void*>(ptr)); } size_t freeObjectCount() const { return m_freeObjects.size(); } void findFreeObjects(TCMalloc_ThreadCache* threadCache) @@ -3680,7 +3712,9 @@ class PageMapMemoryUsageRecorder { vm_range_recorder_t* m_recorder; const RemoteMemoryReader& m_reader; const FreeObjectFinder& m_freeObjectFinder; - mutable HashSet<void*> m_seenPointers; + + HashSet<void*> m_seenPointers; + Vector<Span*> m_coalescedSpans; public: PageMapMemoryUsageRecorder(task_t task, void* context, unsigned typeMask, vm_range_recorder_t* recorder, const RemoteMemoryReader& reader, const FreeObjectFinder& freeObjectFinder) @@ -3692,51 +3726,133 @@ public: , m_freeObjectFinder(freeObjectFinder) { } - int visit(void* ptr) const + ~PageMapMemoryUsageRecorder() + { + ASSERT(!m_coalescedSpans.size()); + } + + void recordPendingRegions() + { + Span* lastSpan = m_coalescedSpans[m_coalescedSpans.size() - 1]; + vm_range_t ptrRange = { m_coalescedSpans[0]->start << kPageShift, 0 }; + ptrRange.size = (lastSpan->start << kPageShift) - ptrRange.address + (lastSpan->length * kPageSize); + + // Mark the memory region the spans represent as a candidate for containing pointers + if (m_typeMask & MALLOC_PTR_REGION_RANGE_TYPE) + (*m_recorder)(m_task, m_context, MALLOC_PTR_REGION_RANGE_TYPE, &ptrRange, 1); + + if (!(m_typeMask & MALLOC_PTR_IN_USE_RANGE_TYPE)) { + m_coalescedSpans.clear(); + return; + } + + Vector<vm_range_t, 1024> allocatedPointers; + for (size_t i = 0; i < m_coalescedSpans.size(); ++i) { + Span *theSpan = m_coalescedSpans[i]; + if (theSpan->free) + continue; + + vm_address_t spanStartAddress = theSpan->start << kPageShift; + vm_size_t spanSizeInBytes = theSpan->length * kPageSize; + + if (!theSpan->sizeclass) { + // If it's an allocated large object span, mark it as in use + if (!m_freeObjectFinder.isFreeObject(spanStartAddress)) + allocatedPointers.append((vm_range_t){spanStartAddress, spanSizeInBytes}); + } else { + const size_t objectSize = ByteSizeForClass(theSpan->sizeclass); + + // Mark each allocated small object within the span as in use + const vm_address_t endOfSpan = spanStartAddress + spanSizeInBytes; + for (vm_address_t object = spanStartAddress; object + objectSize <= endOfSpan; object += objectSize) { + if (!m_freeObjectFinder.isFreeObject(object)) + allocatedPointers.append((vm_range_t){object, objectSize}); + } + } + } + + (*m_recorder)(m_task, m_context, MALLOC_PTR_IN_USE_RANGE_TYPE, allocatedPointers.data(), allocatedPointers.size()); + + m_coalescedSpans.clear(); + } + + int visit(void* ptr) { if (!ptr) return 1; Span* span = m_reader(reinterpret_cast<Span*>(ptr)); + if (!span->start) + return 1; + if (m_seenPointers.contains(ptr)) return span->length; m_seenPointers.add(ptr); - // Mark the memory used for the Span itself as an administrative region - vm_range_t ptrRange = { reinterpret_cast<vm_address_t>(ptr), sizeof(Span) }; - if (m_typeMask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE)) - (*m_recorder)(m_task, m_context, MALLOC_ADMIN_REGION_RANGE_TYPE, &ptrRange, 1); + if (!m_coalescedSpans.size()) { + m_coalescedSpans.append(span); + return span->length; + } - ptrRange.address = span->start << kPageShift; - ptrRange.size = span->length * kPageSize; + Span* previousSpan = m_coalescedSpans[m_coalescedSpans.size() - 1]; + vm_address_t previousSpanStartAddress = previousSpan->start << kPageShift; + vm_size_t previousSpanSizeInBytes = previousSpan->length * kPageSize; - // Mark the memory region the span represents as candidates for containing pointers - if (m_typeMask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE)) - (*m_recorder)(m_task, m_context, MALLOC_PTR_REGION_RANGE_TYPE, &ptrRange, 1); + // If the new span is adjacent to the previous span, do nothing for now. + vm_address_t spanStartAddress = span->start << kPageShift; + if (spanStartAddress == previousSpanStartAddress + previousSpanSizeInBytes) { + m_coalescedSpans.append(span); + return span->length; + } - if (!span->free && (m_typeMask & MALLOC_PTR_IN_USE_RANGE_TYPE)) { - // If it's an allocated large object span, mark it as in use - if (span->sizeclass == 0 && !m_freeObjectFinder.isFreeObject(reinterpret_cast<void*>(ptrRange.address))) - (*m_recorder)(m_task, m_context, MALLOC_PTR_IN_USE_RANGE_TYPE, &ptrRange, 1); - else if (span->sizeclass) { - const size_t byteSize = ByteSizeForClass(span->sizeclass); - unsigned totalObjects = (span->length << kPageShift) / byteSize; - ASSERT(span->refcount <= totalObjects); - char* ptr = reinterpret_cast<char*>(span->start << kPageShift); + // New span is not adjacent to previous span, so record the spans coalesced so far. + recordPendingRegions(); + m_coalescedSpans.append(span); - // Mark each allocated small object within the span as in use - for (unsigned i = 0; i < totalObjects; i++) { - char* thisObject = ptr + (i * byteSize); - if (m_freeObjectFinder.isFreeObject(thisObject)) - continue; + return span->length; + } +}; - vm_range_t objectRange = { reinterpret_cast<vm_address_t>(thisObject), byteSize }; - (*m_recorder)(m_task, m_context, MALLOC_PTR_IN_USE_RANGE_TYPE, &objectRange, 1); - } - } +class AdminRegionRecorder { + task_t m_task; + void* m_context; + unsigned m_typeMask; + vm_range_recorder_t* m_recorder; + const RemoteMemoryReader& m_reader; + + Vector<vm_range_t, 1024> m_pendingRegions; + +public: + AdminRegionRecorder(task_t task, void* context, unsigned typeMask, vm_range_recorder_t* recorder, const RemoteMemoryReader& reader) + : m_task(task) + , m_context(context) + , m_typeMask(typeMask) + , m_recorder(recorder) + , m_reader(reader) + { } + + void recordRegion(vm_address_t ptr, size_t size) + { + if (m_typeMask & MALLOC_ADMIN_REGION_RANGE_TYPE) + m_pendingRegions.append((vm_range_t){ ptr, size }); + } + + void visit(void *ptr, size_t size) + { + recordRegion(reinterpret_cast<vm_address_t>(ptr), size); + } + + void recordPendingRegions() + { + if (m_pendingRegions.size()) { + (*m_recorder)(m_task, m_context, MALLOC_ADMIN_REGION_RANGE_TYPE, m_pendingRegions.data(), m_pendingRegions.size()); + m_pendingRegions.clear(); } + } - return span->length; + ~AdminRegionRecorder() + { + ASSERT(!m_pendingRegions.size()); } }; @@ -3759,10 +3875,22 @@ kern_return_t FastMallocZone::enumerate(task_t task, void* context, unsigned typ TCMalloc_PageHeap::PageMap* pageMap = &pageHeap->pagemap_; PageMapFreeObjectFinder pageMapFinder(memoryReader, finder); - pageMap->visit(pageMapFinder, memoryReader); + pageMap->visitValues(pageMapFinder, memoryReader); PageMapMemoryUsageRecorder usageRecorder(task, context, typeMask, recorder, memoryReader, finder); - pageMap->visit(usageRecorder, memoryReader); + pageMap->visitValues(usageRecorder, memoryReader); + usageRecorder.recordPendingRegions(); + + AdminRegionRecorder adminRegionRecorder(task, context, typeMask, recorder, memoryReader); + pageMap->visitAllocations(adminRegionRecorder, memoryReader); + + PageHeapAllocator<Span>* spanAllocator = memoryReader(mzone->m_spanAllocator); + PageHeapAllocator<TCMalloc_ThreadCache>* pageHeapAllocator = memoryReader(mzone->m_pageHeapAllocator); + + spanAllocator->recordAdministrativeRegions(adminRegionRecorder, memoryReader); + pageHeapAllocator->recordAdministrativeRegions(adminRegionRecorder, memoryReader); + + adminRegionRecorder.recordPendingRegions(); return 0; } @@ -3803,15 +3931,24 @@ void* FastMallocZone::zoneRealloc(malloc_zone_t*, void*, size_t) extern "C" { malloc_introspection_t jscore_fastmalloc_introspection = { &FastMallocZone::enumerate, &FastMallocZone::goodSize, &FastMallocZone::check, &FastMallocZone::print, - &FastMallocZone::log, &FastMallocZone::forceLock, &FastMallocZone::forceUnlock, &FastMallocZone::statistics }; + &FastMallocZone::log, &FastMallocZone::forceLock, &FastMallocZone::forceUnlock, &FastMallocZone::statistics + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + , 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher. +#endif + + }; } -FastMallocZone::FastMallocZone(TCMalloc_PageHeap* pageHeap, TCMalloc_ThreadCache** threadHeaps, TCMalloc_Central_FreeListPadded* centralCaches) +FastMallocZone::FastMallocZone(TCMalloc_PageHeap* pageHeap, TCMalloc_ThreadCache** threadHeaps, TCMalloc_Central_FreeListPadded* centralCaches, PageHeapAllocator<Span>* spanAllocator, PageHeapAllocator<TCMalloc_ThreadCache>* pageHeapAllocator) : m_pageHeap(pageHeap) , m_threadHeaps(threadHeaps) , m_centralCaches(centralCaches) + , m_spanAllocator(spanAllocator) + , m_pageHeapAllocator(pageHeapAllocator) { memset(&m_zone, 0, sizeof(m_zone)); + m_zone.version = 4; m_zone.zone_name = "JavaScriptCore FastMalloc"; m_zone.size = &FastMallocZone::size; m_zone.malloc = &FastMallocZone::zoneMalloc; @@ -3827,7 +3964,7 @@ FastMallocZone::FastMallocZone(TCMalloc_PageHeap* pageHeap, TCMalloc_ThreadCache void FastMallocZone::init() { - static FastMallocZone zone(pageheap, &thread_heaps, static_cast<TCMalloc_Central_FreeListPadded*>(central_cache)); + static FastMallocZone zone(pageheap, &thread_heaps, static_cast<TCMalloc_Central_FreeListPadded*>(central_cache), &span_allocator, &threadheap_allocator); } #endif diff --git a/JavaScriptCore/wtf/HashTraits.h b/JavaScriptCore/wtf/HashTraits.h index b3c0b7a..c8d40f7 100644 --- a/JavaScriptCore/wtf/HashTraits.h +++ b/JavaScriptCore/wtf/HashTraits.h @@ -21,8 +21,8 @@ #ifndef WTF_HashTraits_h #define WTF_HashTraits_h -#include "Assertions.h" #include "HashFunctions.h" +#include "TypeTraits.h" #include <utility> #include <limits> @@ -31,47 +31,6 @@ namespace WTF { using std::pair; using std::make_pair; - template<typename T> struct IsInteger { static const bool value = false; }; - template<> struct IsInteger<bool> { static const bool value = true; }; - template<> struct IsInteger<char> { static const bool value = true; }; - template<> struct IsInteger<signed char> { static const bool value = true; }; - template<> struct IsInteger<unsigned char> { static const bool value = true; }; - template<> struct IsInteger<short> { static const bool value = true; }; - template<> struct IsInteger<unsigned short> { static const bool value = true; }; - template<> struct IsInteger<int> { static const bool value = true; }; - template<> struct IsInteger<unsigned int> { static const bool value = true; }; - template<> struct IsInteger<long> { static const bool value = true; }; - template<> struct IsInteger<unsigned long> { static const bool value = true; }; - template<> struct IsInteger<long long> { static const bool value = true; }; - template<> struct IsInteger<unsigned long long> { static const bool value = true; }; - -#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) - template<> struct IsInteger<wchar_t> { static const bool value = true; }; -#endif - - COMPILE_ASSERT(IsInteger<bool>::value, WTF_IsInteger_bool_true); - COMPILE_ASSERT(IsInteger<char>::value, WTF_IsInteger_char_true); - COMPILE_ASSERT(IsInteger<signed char>::value, WTF_IsInteger_signed_char_true); - COMPILE_ASSERT(IsInteger<unsigned char>::value, WTF_IsInteger_unsigned_char_true); - COMPILE_ASSERT(IsInteger<short>::value, WTF_IsInteger_short_true); - COMPILE_ASSERT(IsInteger<unsigned short>::value, WTF_IsInteger_unsigned_short_true); - COMPILE_ASSERT(IsInteger<int>::value, WTF_IsInteger_int_true); - COMPILE_ASSERT(IsInteger<unsigned int>::value, WTF_IsInteger_unsigned_int_true); - COMPILE_ASSERT(IsInteger<long>::value, WTF_IsInteger_long_true); - COMPILE_ASSERT(IsInteger<unsigned long>::value, WTF_IsInteger_unsigned_long_true); - COMPILE_ASSERT(IsInteger<long long>::value, WTF_IsInteger_long_long_true); - COMPILE_ASSERT(IsInteger<unsigned long long>::value, WTF_IsInteger_unsigned_long_long_true); - -#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) - COMPILE_ASSERT(IsInteger<wchar_t>::value, WTF_IsInteger_wchar_t_true); -#endif - - COMPILE_ASSERT(!IsInteger<char*>::value, WTF_IsInteger_char_pointer_false); - COMPILE_ASSERT(!IsInteger<const char* >::value, WTF_IsInteger_const_char_pointer_false); - COMPILE_ASSERT(!IsInteger<volatile char* >::value, WTF_IsInteger_volatile_char_pointer__false); - COMPILE_ASSERT(!IsInteger<double>::value, WTF_IsInteger_double_false); - COMPILE_ASSERT(!IsInteger<float>::value, WTF_IsInteger_float_false); - template<typename T> struct HashTraits; template<bool isInteger, typename T> struct GenericHashTraitsBase; diff --git a/JavaScriptCore/wtf/MainThread.cpp b/JavaScriptCore/wtf/MainThread.cpp index c7a6caa..3c19b7a 100644 --- a/JavaScriptCore/wtf/MainThread.cpp +++ b/JavaScriptCore/wtf/MainThread.cpp @@ -29,26 +29,25 @@ #include "config.h" #include "MainThread.h" +#include "CurrentTime.h" +#include "Deque.h" #include "StdLibExtras.h" #include "Threading.h" -#include "Vector.h" namespace WTF { struct FunctionWithContext { MainThreadFunction* function; void* context; - ThreadCondition* syncFlag; - FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0) + FunctionWithContext(MainThreadFunction* function = 0, void* context = 0) : function(function) , context(context) - , syncFlag(syncFlag) { } }; -typedef Vector<FunctionWithContext> FunctionQueue; +typedef Deque<FunctionWithContext> FunctionQueue; static bool callbacksPaused; // This global variable is only accessed from main thread. @@ -64,12 +63,14 @@ static FunctionQueue& functionQueue() return staticFunctionQueue; } -#if !PLATFORM(WIN) void initializeMainThread() { mainThreadFunctionQueueMutex(); + initializeMainThreadPlatform(); } -#endif + +// 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that. +static const double maxRunLoopSuspensionTime = 0.05; void dispatchFunctionsFromMainThread() { @@ -78,52 +79,42 @@ void dispatchFunctionsFromMainThread() if (callbacksPaused) return; - FunctionQueue queueCopy; - { - MutexLocker locker(mainThreadFunctionQueueMutex()); - queueCopy.swap(functionQueue()); - } + double startTime = currentTime(); + + FunctionWithContext invocation; + while (true) { + { + MutexLocker locker(mainThreadFunctionQueueMutex()); + if (!functionQueue().size()) + break; + invocation = functionQueue().first(); + functionQueue().removeFirst(); + } - for (unsigned i = 0; i < queueCopy.size(); ++i) { - FunctionWithContext& invocation = queueCopy[i]; invocation.function(invocation.context); - if (invocation.syncFlag) - invocation.syncFlag->signal(); + + // If we are running accumulated functions for too long so UI may become unresponsive, we need to + // yield so the user input can be processed. Otherwise user may not be able to even close the window. + // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that + // allows input events to be processed before we are back here. + if (currentTime() - startTime > maxRunLoopSuspensionTime) { + scheduleDispatchFunctionsOnMainThread(); + break; + } } } void callOnMainThread(MainThreadFunction* function, void* context) { ASSERT(function); - + bool needToSchedule = false; { MutexLocker locker(mainThreadFunctionQueueMutex()); + needToSchedule = functionQueue().size() == 0; functionQueue().append(FunctionWithContext(function, context)); } - - scheduleDispatchFunctionsOnMainThread(); -} - -void callOnMainThreadAndWait(MainThreadFunction* function, void* context) -{ - ASSERT(function); - - if (isMainThread()) { - function(context); - return; - } - - ThreadCondition syncFlag; - Mutex conditionMutex; - - { - MutexLocker locker(mainThreadFunctionQueueMutex()); - functionQueue().append(FunctionWithContext(function, context, &syncFlag)); - conditionMutex.lock(); - } - - scheduleDispatchFunctionsOnMainThread(); - syncFlag.wait(conditionMutex); + if (needToSchedule) + scheduleDispatchFunctionsOnMainThread(); } void setMainThreadCallbacksPaused(bool paused) diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h index 953b986..01ce804 100644 --- a/JavaScriptCore/wtf/MainThread.h +++ b/JavaScriptCore/wtf/MainThread.h @@ -37,7 +37,6 @@ class Mutex; typedef void MainThreadFunction(void*); void callOnMainThread(MainThreadFunction*, void* context); -void callOnMainThreadAndWait(MainThreadFunction*, void* context); void setMainThreadCallbacksPaused(bool paused); @@ -45,9 +44,10 @@ void setMainThreadCallbacksPaused(bool paused); void initializeMainThread(); // These functions are internal to the callOnMainThread implementation. -void dispatchFunctionsFromMainThread(); +void initializeMainThreadPlatform(); void scheduleDispatchFunctionsOnMainThread(); Mutex& mainThreadFunctionQueueMutex(); +void dispatchFunctionsFromMainThread(); } // namespace WTF diff --git a/JavaScriptCore/wtf/MessageQueue.h b/JavaScriptCore/wtf/MessageQueue.h index 19c5c10..9549f37 100644 --- a/JavaScriptCore/wtf/MessageQueue.h +++ b/JavaScriptCore/wtf/MessageQueue.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +30,7 @@ #ifndef MessageQueue_h #define MessageQueue_h +#include <limits> #include <wtf/Assertions.h> #include <wtf/Deque.h> #include <wtf/Noncopyable.h> @@ -50,7 +52,8 @@ namespace WTF { void append(const DataType&); void prepend(const DataType&); bool waitForMessage(DataType&); - MessageQueueWaitResult waitForMessageTimed(DataType&, double absoluteTime); + template<typename Predicate> + MessageQueueWaitResult waitForMessageFilteredWithTimeout(DataType&, Predicate&, double absoluteTime); void kill(); bool tryGetMessage(DataType&); @@ -59,7 +62,11 @@ namespace WTF { // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time. bool isEmpty(); + static double infiniteTime() { return std::numeric_limits<double>::max(); } + private: + static bool alwaysTruePredicate(DataType&) { return true; } + mutable Mutex m_mutex; ThreadCondition m_condition; Deque<DataType> m_queue; @@ -85,38 +92,33 @@ namespace WTF { template<typename DataType> inline bool MessageQueue<DataType>::waitForMessage(DataType& result) { - MutexLocker lock(m_mutex); - - while (!m_killed && m_queue.isEmpty()) - m_condition.wait(m_mutex); - - if (m_killed) - return false; - - ASSERT(!m_queue.isEmpty()); - result = m_queue.first(); - m_queue.removeFirst(); - return true; + MessageQueueWaitResult exitReason = waitForMessageFilteredWithTimeout(result, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime()); + ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived); + return exitReason == MessageQueueMessageReceived; } template<typename DataType> - inline MessageQueueWaitResult MessageQueue<DataType>::waitForMessageTimed(DataType& result, double absoluteTime) + template<typename Predicate> + inline MessageQueueWaitResult MessageQueue<DataType>::waitForMessageFilteredWithTimeout(DataType& result, Predicate& predicate, double absoluteTime) { MutexLocker lock(m_mutex); bool timedOut = false; - while (!m_killed && !timedOut && m_queue.isEmpty()) + DequeConstIterator<DataType> found = m_queue.end(); + while (!m_killed && !timedOut && (found = m_queue.findIf(predicate)) == m_queue.end()) timedOut = !m_condition.timedWait(m_mutex, absoluteTime); + ASSERT(!timedOut || absoluteTime != infiniteTime()); + if (m_killed) return MessageQueueTerminated; if (timedOut) return MessageQueueTimeout; - ASSERT(!m_queue.isEmpty()); - result = m_queue.first(); - m_queue.removeFirst(); + ASSERT(found != m_queue.end()); + result = *found; + m_queue.remove(found); return MessageQueueMessageReceived; } @@ -157,7 +159,7 @@ namespace WTF { MutexLocker lock(m_mutex); return m_killed; } -} +} // namespace WTF using WTF::MessageQueue; // MessageQueueWaitResult enum and all its values. diff --git a/JavaScriptCore/wtf/OwnPtr.h b/JavaScriptCore/wtf/OwnPtr.h index 256b55c..af939e7 100644 --- a/JavaScriptCore/wtf/OwnPtr.h +++ b/JavaScriptCore/wtf/OwnPtr.h @@ -21,10 +21,11 @@ #ifndef WTF_OwnPtr_h #define WTF_OwnPtr_h +#include "Assertions.h" +#include "Noncopyable.h" +#include "TypeTraits.h" #include <algorithm> #include <memory> -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> #if PLATFORM(WIN) @@ -41,10 +42,6 @@ namespace WTF { // Unlike most of our smart pointers, OwnPtr can take either the pointer type or the pointed-to type. - // FIXME: Share a single RemovePointer class template with RetainPtr. - template <typename T> struct OwnPtrRemovePointer { typedef T type; }; - template <typename T> struct OwnPtrRemovePointer<T*> { typedef T type; }; - template <typename T> inline void deleteOwnedPtr(T* ptr) { typedef char known[sizeof(T) ? 1 : -1]; @@ -63,7 +60,7 @@ namespace WTF { template <typename T> class OwnPtr : Noncopyable { public: - typedef typename OwnPtrRemovePointer<T>::type ValueType; + typedef typename RemovePointer<T>::Type ValueType; typedef ValueType* PtrType; explicit OwnPtr(PtrType ptr = 0) : m_ptr(ptr) { } diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index fea00c4..1813114 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -40,6 +40,12 @@ /* be used regardless of operating environment */ #ifdef __APPLE__ #define WTF_PLATFORM_DARWIN 1 +#include <AvailabilityMacros.h> +#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 +#define BUILDING_ON_TIGER 1 +#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 +#define BUILDING_ON_LEOPARD 1 +#endif #endif /* PLATFORM(WIN_OS) */ @@ -238,6 +244,11 @@ #define WTF_PLATFORM_X86_64 1 #endif +/* PLATFORM(SH4) */ +#if defined(__SH4__) +#define WTF_PLATFORM_SH4 1 +#endif + /* PLATFORM(SPARC64) */ #if defined(__sparc64__) #define WTF_PLATFORM_SPARC64 1 @@ -268,8 +279,14 @@ #endif #endif +/* COMPILER(RVCT) */ +#if defined(__CC_ARM) || defined(__ARMCC__) +#define WTF_COMPILER_RVCT 1 +#endif + /* COMPILER(GCC) */ -#if defined(__GNUC__) +/* --gnu option of the RVCT compiler also defines __GNUC__ */ +#if defined(__GNUC__) && !COMPILER(RVCT) #define WTF_COMPILER_GCC 1 #endif @@ -290,11 +307,6 @@ #define WTF_COMPILER_CYGWIN 1 #endif -/* COMPILER(RVCT) */ -#if defined(__CC_ARM) || defined(__ARMCC__) -#define WTF_COMPILER_RVCT 1 -#endif - /* COMPILER(WINSCW) */ #if defined(__WINSCW__) #define WTF_COMPILER_WINSCW 1 @@ -325,9 +337,7 @@ #define ENABLE_DASHBOARD_SUPPORT 1 #endif #define HAVE_READLINE 1 -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) -#define HAVE_DTRACE 1 -#endif +#define HAVE_RUNLOOP_TIMER 1 #endif #if PLATFORM(CHROMIUM) && PLATFORM(DARWIN) @@ -363,6 +373,7 @@ #if PLATFORM(DARWIN) #define HAVE_ERRNO_H 1 +#define HAVE_LANGINFO_H 1 #define HAVE_MMAP 1 #define HAVE_MERGESORT 1 #define HAVE_SBRK 1 @@ -371,6 +382,10 @@ #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMEB_H 1 +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#define HAVE_MADV_FREE_REUSE 1 +#endif + #elif PLATFORM(WIN_OS) #define HAVE_FLOAT_H 1 @@ -394,11 +409,22 @@ #define HAVE_SYS_PARAM_H 1 #endif +#elif PLATFORM(ANDROID) + +#define HAVE_ERRNO_H 1 +#define HAVE_LANGINFO_H 0 +#define HAVE_MMAP 1 +#define HAVE_SBRK 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 + #else /* FIXME: is this actually used or do other platforms generate their own config.h? */ #define HAVE_ERRNO_H 1 +#define HAVE_LANGINFO_H 1 #define HAVE_MMAP 1 #define HAVE_SBRK 1 #define HAVE_STRINGS_H 1 @@ -466,14 +492,22 @@ #define ENABLE_ARCHIVE 1 #endif +#if !defined(ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL) +#define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0 +#endif + #if !defined(WTF_USE_ALTERNATE_JSIMMEDIATE) && PLATFORM(X86_64) && PLATFORM(MAC) #define WTF_USE_ALTERNATE_JSIMMEDIATE 1 #endif +#if !defined(ENABLE_REPAINT_THROTTLING) +#define ENABLE_REPAINT_THROTTLING 0 +#endif + #if !defined(ENABLE_JIT) -/* x86-64 support is under development. */ +/* The JIT is tested & working on x86_64 Mac */ #if PLATFORM(X86_64) && PLATFORM(MAC) - #define ENABLE_JIT 0 + #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 /* The JIT is tested & working on x86 Mac */ #elif PLATFORM(X86) && PLATFORM(MAC) diff --git a/JavaScriptCore/wtf/RefCounted.h b/JavaScriptCore/wtf/RefCounted.h index ac8e167..93ee0da 100644 --- a/JavaScriptCore/wtf/RefCounted.h +++ b/JavaScriptCore/wtf/RefCounted.h @@ -49,8 +49,8 @@ public: } protected: - RefCountedBase(int initialRefCount) - : m_refCount(initialRefCount) + RefCountedBase() + : m_refCount(1) #ifndef NDEBUG , m_deletionHasBegun(false) #endif @@ -76,6 +76,9 @@ protected: } protected: + template<class T> + friend class CrossThreadRefCounted; + int m_refCount; #ifndef NDEBUG bool m_deletionHasBegun; @@ -85,11 +88,6 @@ protected: template<class T> class RefCounted : public RefCountedBase { public: - RefCounted(int initialRefCount = 1) - : RefCountedBase(initialRefCount) - { - } - void deref() { if (derefBase()) diff --git a/JavaScriptCore/wtf/RetainPtr.h b/JavaScriptCore/wtf/RetainPtr.h index a66a127..77f25e0 100644 --- a/JavaScriptCore/wtf/RetainPtr.h +++ b/JavaScriptCore/wtf/RetainPtr.h @@ -21,6 +21,7 @@ #ifndef RetainPtr_h #define RetainPtr_h +#include "TypeTraits.h" #include <algorithm> #include <CoreFoundation/CoreFoundation.h> @@ -30,14 +31,6 @@ namespace WTF { - template <typename T> struct RemovePointer { - typedef T type; - }; - - template <typename T> struct RemovePointer<T*> { - typedef T type; - }; - // Unlike most most of our smart pointers, RetainPtr can take either the pointer type or the pointed-to type, // so both RetainPtr<NSDictionary> and RetainPtr<CFDictionaryRef> will work. @@ -56,7 +49,7 @@ namespace WTF { template <typename T> class RetainPtr { public: - typedef typename RemovePointer<T>::type ValueType; + typedef typename RemovePointer<T>::Type ValueType; typedef ValueType* PtrType; RetainPtr() : m_ptr(0) {} diff --git a/JavaScriptCore/wtf/TCPageMap.h b/JavaScriptCore/wtf/TCPageMap.h index 3e6b80e..9ffd77b 100644 --- a/JavaScriptCore/wtf/TCPageMap.h +++ b/JavaScriptCore/wtf/TCPageMap.h @@ -54,7 +54,6 @@ #endif #include <string.h> - #include "Assertions.h" // Single-level array @@ -164,7 +163,7 @@ class TCMalloc_PageMap2 { #ifdef WTF_CHANGES template<class Visitor, class MemoryReader> - void visit(const Visitor& visitor, const MemoryReader& reader) + void visitValues(Visitor& visitor, const MemoryReader& reader) { for (int i = 0; i < ROOT_LENGTH; i++) { if (!root_[i]) @@ -175,6 +174,14 @@ class TCMalloc_PageMap2 { ; } } + + template<class Visitor, class MemoryReader> + void visitAllocations(Visitor& visitor, const MemoryReader&) { + for (int i = 0; i < ROOT_LENGTH; i++) { + if (root_[i]) + visitor.visit(root_[i], sizeof(Leaf)); + } + } #endif }; @@ -266,7 +273,7 @@ class TCMalloc_PageMap3 { #ifdef WTF_CHANGES template<class Visitor, class MemoryReader> - void visit(const Visitor& visitor, const MemoryReader& reader) { + void visitValues(Visitor& visitor, const MemoryReader& reader) { Node* root = reader(root_); for (int i = 0; i < INTERIOR_LENGTH; i++) { if (!root->ptrs[i]) @@ -283,6 +290,26 @@ class TCMalloc_PageMap3 { } } } + + template<class Visitor, class MemoryReader> + void visitAllocations(Visitor& visitor, const MemoryReader& reader) { + visitor.visit(root_, sizeof(Node)); + + Node* root = reader(root_); + for (int i = 0; i < INTERIOR_LENGTH; i++) { + if (!root->ptrs[i]) + continue; + + visitor.visit(root->ptrs[i], sizeof(Node)); + Node* n = reader(root->ptrs[i]); + for (int j = 0; j < INTERIOR_LENGTH; j++) { + if (!n->ptrs[j]) + continue; + + visitor.visit(n->ptrs[j], sizeof(Leaf)); + } + } + } #endif }; diff --git a/JavaScriptCore/wtf/TCSystemAlloc.cpp b/JavaScriptCore/wtf/TCSystemAlloc.cpp index 3a8908d..bf2dcb1 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.cpp +++ b/JavaScriptCore/wtf/TCSystemAlloc.cpp @@ -381,9 +381,17 @@ void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) { return NULL; } +#if HAVE(MADV_FREE_REUSE) + +void TCMalloc_SystemRelease(void* start, size_t length) +{ + while (madvise(start, length, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +} + +#elif HAVE(MADV_DONTNEED) + void TCMalloc_SystemRelease(void* start, size_t length) { -#if HAVE(MADV_DONTNEED) if (FLAGS_malloc_devmem_start) { // It's not safe to use MADV_DONTNEED if we've been mapping // /dev/mem for heap memory @@ -414,25 +422,41 @@ void TCMalloc_SystemRelease(void* start, size_t length) errno == EAGAIN) { // NOP } - return; } -#endif +} -#if HAVE(MMAP) +#elif HAVE(MMAP) + +void TCMalloc_SystemRelease(void* start, size_t length) +{ void* newAddress = mmap(start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); // If the mmap failed then that's ok, we just won't return the memory to the system. ASSERT_UNUSED(newAddress, newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED)); - return; -#endif +} + +#else + +// Platforms that don't support returning memory use an empty inline version of TCMalloc_SystemRelease +// declared in TCSystemAlloc.h -#if !HAVE(MADV_DONTNEED) && !HAVE(MMAP) - UNUSED_PARAM(start); - UNUSED_PARAM(length); #endif + +#if HAVE(MADV_FREE_REUSE) + +void TCMalloc_SystemCommit(void* start, size_t length) +{ + while (madvise(start, length, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } } -#if HAVE(VIRTUALALLOC) +#elif HAVE(VIRTUALALLOC) + void TCMalloc_SystemCommit(void*, size_t) { } + +#else + +// Platforms that don't need to explicitly commit memory use an empty inline version of TCMalloc_SystemCommit +// declared in TCSystemAlloc.h + #endif diff --git a/JavaScriptCore/wtf/TCSystemAlloc.h b/JavaScriptCore/wtf/TCSystemAlloc.h index d82e860..f2c915e 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.h +++ b/JavaScriptCore/wtf/TCSystemAlloc.h @@ -62,9 +62,13 @@ extern void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes, // be released, partial pages will not.) extern void TCMalloc_SystemRelease(void* start, size_t length); -#if HAVE(VIRTUALALLOC) extern void TCMalloc_SystemCommit(void* start, size_t length); -#else + +#if !HAVE(MADV_FREE_REUSE) && !HAVE(MADV_DONTNEED) && !HAVE(MMAP) +inline void TCMalloc_SystemRelease(void*, size_t) { } +#endif + +#if !HAVE(VIRTUALALLOC) && !HAVE(MADV_FREE_REUSE) inline void TCMalloc_SystemCommit(void*, size_t) { } #endif diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h index 7603802..8aaaf5f 100644 --- a/JavaScriptCore/wtf/ThreadSpecific.h +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -129,8 +129,8 @@ inline void ThreadSpecific<T>::set(T* ptr) // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough. const int kMaxTlsKeySize = 256; -extern long g_tls_key_count; -extern DWORD g_tls_keys[kMaxTlsKeySize]; +long& tlsKeyCount(); +DWORD* tlsKeys(); template<typename T> inline ThreadSpecific<T>::ThreadSpecific() @@ -140,23 +140,23 @@ inline ThreadSpecific<T>::ThreadSpecific() if (tls_key == TLS_OUT_OF_INDEXES) CRASH(); - m_index = InterlockedIncrement(&g_tls_key_count) - 1; + m_index = InterlockedIncrement(&tlsKeyCount()) - 1; if (m_index >= kMaxTlsKeySize) CRASH(); - g_tls_keys[m_index] = tls_key; + tlsKeys()[m_index] = tls_key; } template<typename T> inline ThreadSpecific<T>::~ThreadSpecific() { // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached. - TlsFree(g_tls_keys[m_index]); + TlsFree(tlsKeys()[m_index]); } template<typename T> inline T* ThreadSpecific<T>::get() { - Data* data = static_cast<Data*>(TlsGetValue(g_tls_keys[m_index])); + Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); return data ? data->value : 0; } @@ -166,7 +166,7 @@ inline void ThreadSpecific<T>::set(T* ptr) ASSERT(!get()); Data* data = new Data(ptr, this); data->destructor = &ThreadSpecific<T>::destroy; - TlsSetValue(g_tls_keys[m_index], data); + TlsSetValue(tlsKeys()[m_index], data); } #else @@ -190,7 +190,7 @@ inline void ThreadSpecific<T>::destroy(void* ptr) #if USE(PTHREADS) pthread_setspecific(data->owner->m_key, 0); #elif PLATFORM(WIN_OS) - TlsSetValue(g_tls_keys[data->owner->m_index], 0); + TlsSetValue(tlsKeys()[data->owner->m_index], 0); #else #error ThreadSpecific is not implemented for this platform. #endif diff --git a/JavaScriptCore/wtf/ThreadSpecificWin.cpp b/JavaScriptCore/wtf/ThreadSpecificWin.cpp index 1a3febb..f2c0cad 100644 --- a/JavaScriptCore/wtf/ThreadSpecificWin.cpp +++ b/JavaScriptCore/wtf/ThreadSpecificWin.cpp @@ -29,14 +29,23 @@ namespace WTF { -long g_tls_key_count = 0; -DWORD g_tls_keys[kMaxTlsKeySize]; +long& tlsKeyCount() +{ + static long count; + return count; +} + +DWORD* tlsKeys() +{ + static DWORD keys[kMaxTlsKeySize]; + return keys; +} void ThreadSpecificThreadExit() { - for (long i = 0; i < g_tls_key_count; i++) { + for (long i = 0; i < tlsKeyCount(); i++) { // The layout of ThreadSpecific<T>::Data does not depend on T. So we are safe to do the static cast to ThreadSpecific<int> in order to access its data member. - ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(g_tls_keys[i])); + ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i])); if (data) data->destructor(data); } diff --git a/JavaScriptCore/wtf/Threading.cpp b/JavaScriptCore/wtf/Threading.cpp index 41c9135..bd25ee7 100644 --- a/JavaScriptCore/wtf/Threading.cpp +++ b/JavaScriptCore/wtf/Threading.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,16 +26,21 @@ #include "config.h" #include "Threading.h" +#include <string.h> + namespace WTF { struct NewThreadContext { - NewThreadContext(ThreadFunction entryPoint, void* data) + NewThreadContext(ThreadFunction entryPoint, void* data, const char* name) : entryPoint(entryPoint) , data(data) - { } + , name(name) + { + } ThreadFunction entryPoint; void* data; + const char* name; Mutex creationMutex; }; @@ -44,6 +49,8 @@ static void* threadEntryPoint(void* contextData) { NewThreadContext* context = reinterpret_cast<NewThreadContext*>(contextData); + setThreadNameInternal(context->name); + // Block until our creating thread has completed any extra setup work { MutexLocker locker(context->creationMutex); @@ -59,7 +66,14 @@ static void* threadEntryPoint(void* contextData) ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name) { - NewThreadContext* context = new NewThreadContext(entryPoint, data); + // Visual Studio has a 31-character limit on thread names. Longer names will + // be truncated silently, but we'd like callers to know about the limit. +#if !LOG_DISABLED + if (strlen(name) > 31) + LOG_ERROR("Thread name \"%s\" is longer than 31 characters and will be truncated by Visual Studio", name); +#endif + + NewThreadContext* context = new NewThreadContext(entryPoint, data, name); // Prevent the thread body from executing until we've established the thread identifier MutexLocker locker(context->creationMutex); diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h index 1c0dab1..e562f35 100644 --- a/JavaScriptCore/wtf/Threading.h +++ b/JavaScriptCore/wtf/Threading.h @@ -110,10 +110,17 @@ namespace WTF { typedef uint32_t ThreadIdentifier; typedef void* (*ThreadFunction)(void* argument); -// Returns 0 if thread creation failed +// Returns 0 if thread creation failed. +// The thread name must be a literal since on some platforms it's passed in to the thread. ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); + +// Internal platform-specific createThread implementation. ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName); +// Called in the thread during initialization. +// Helpful for platforms where the thread name must be set from within the thread. +void setThreadNameInternal(const char* threadName); + ThreadIdentifier currentThread(); bool isMainThread(); int waitForThreadCompletion(ThreadIdentifier, void**); @@ -212,9 +219,9 @@ inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_ #endif -template<class T> class ThreadSafeShared : Noncopyable { +class ThreadSafeSharedBase : Noncopyable { public: - ThreadSafeShared(int initialRefCount = 1) + ThreadSafeSharedBase(int initialRefCount = 1) : m_refCount(initialRefCount) { } @@ -229,20 +236,6 @@ public: #endif } - void deref() - { -#if USE(LOCKFREE_THREADSAFESHARED) - if (atomicDecrement(&m_refCount) <= 0) -#else - { - MutexLocker locker(m_mutex); - --m_refCount; - } - if (m_refCount <= 0) -#endif - delete static_cast<T*>(this); - } - bool hasOneRef() { return refCount() == 1; @@ -256,13 +249,50 @@ public: return static_cast<int const volatile &>(m_refCount); } +protected: + // Returns whether the pointer should be freed or not. + bool derefBase() + { +#if USE(LOCKFREE_THREADSAFESHARED) + if (atomicDecrement(&m_refCount) <= 0) + return true; +#else + int refCount; + { + MutexLocker locker(m_mutex); + --m_refCount; + refCount = m_refCount; + } + if (refCount <= 0) + return true; +#endif + return false; + } + private: + template<class T> + friend class CrossThreadRefCounted; + int m_refCount; #if !USE(LOCKFREE_THREADSAFESHARED) mutable Mutex m_mutex; #endif }; +template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { +public: + ThreadSafeShared(int initialRefCount = 1) + : ThreadSafeSharedBase(initialRefCount) + { + } + + void deref() + { + if (derefBase()) + delete static_cast<T*>(this); + } +}; + // This function must be called from the main thread. It is safe to call it repeatedly. // Darwin is an exception to this rule: it is OK to call it from any thread, the only requirement is that the calls are not reentrant. void initializeThreading(); diff --git a/JavaScriptCore/wtf/ThreadingGtk.cpp b/JavaScriptCore/wtf/ThreadingGtk.cpp index 24c34ca..b4f4de1 100644 --- a/JavaScriptCore/wtf/ThreadingGtk.cpp +++ b/JavaScriptCore/wtf/ThreadingGtk.cpp @@ -138,6 +138,10 @@ ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con return threadID; } +void setThreadNameInternal(const char*) +{ +} + int waitForThreadCompletion(ThreadIdentifier threadID, void** result) { ASSERT(threadID); diff --git a/JavaScriptCore/wtf/ThreadingNone.cpp b/JavaScriptCore/wtf/ThreadingNone.cpp index 0be2a4b..24431fc 100644 --- a/JavaScriptCore/wtf/ThreadingNone.cpp +++ b/JavaScriptCore/wtf/ThreadingNone.cpp @@ -34,6 +34,7 @@ namespace WTF { void initializeThreading() { } ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char*) { return 0; } +void setThreadNameInternal(const char*) { } int waitForThreadCompletion(ThreadIdentifier, void**) { return 0; } void detachThread(ThreadIdentifier) { } ThreadIdentifier currentThread() { return 0; } diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp index 105e42a..42133bc 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -26,18 +26,18 @@ * (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 "Threading.h" -#include "StdLibExtras.h" - #if USE(PTHREADS) #include "CurrentTime.h" #include "HashMap.h" #include "MainThread.h" #include "RandomNumberSeed.h" - +#include "StdLibExtras.h" +#include "UnusedParam.h" #include <errno.h> #include <limits.h> #include <sys/time.h> @@ -48,7 +48,7 @@ typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap; static Mutex* atomicallyInitializedStaticMutex; -#if !PLATFORM(DARWIN) +#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM) static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread. #endif @@ -64,7 +64,7 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); -#if !PLATFORM(DARWIN) +#if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM) mainThreadIdentifier = currentThread(); #endif initializeMainThread(); @@ -133,7 +133,7 @@ static void clearPthreadHandleForIdentifier(ThreadIdentifier id) ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*) { pthread_t threadHandle; - if (pthread_create(&threadHandle, NULL, entryPoint, data)) { + if (pthread_create(&threadHandle, 0, entryPoint, data)) { LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data); return 0; } @@ -141,6 +141,15 @@ ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con return establishIdentifierForPthreadHandle(threadHandle); } +void setThreadNameInternal(const char* threadName) +{ +#if PLATFORM(DARWIN) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + pthread_setname_np(threadName); +#else + UNUSED_PARAM(threadName); +#endif +} + int waitForThreadCompletion(ThreadIdentifier threadID, void** result) { ASSERT(threadID); @@ -176,7 +185,7 @@ ThreadIdentifier currentThread() bool isMainThread() { -#if PLATFORM(DARWIN) +#if PLATFORM(DARWIN) && !PLATFORM(CHROMIUM) return pthread_main_np(); #else return currentThread() == mainThreadIdentifier; @@ -195,8 +204,8 @@ Mutex::~Mutex() void Mutex::lock() { - if (pthread_mutex_lock(&m_mutex) != 0) - ASSERT(false); + int result = pthread_mutex_lock(&m_mutex); + ASSERT_UNUSED(result, !result); } bool Mutex::tryLock() @@ -205,17 +214,17 @@ bool Mutex::tryLock() if (result == 0) return true; - else if (result == EBUSY) + if (result == EBUSY) return false; - ASSERT(false); + ASSERT_NOT_REACHED(); return false; } void Mutex::unlock() { - if (pthread_mutex_unlock(&m_mutex) != 0) - ASSERT(false); + int result = pthread_mutex_unlock(&m_mutex); + ASSERT_UNUSED(result, !result); } ThreadCondition::ThreadCondition() @@ -230,8 +239,8 @@ ThreadCondition::~ThreadCondition() void ThreadCondition::wait(Mutex& mutex) { - if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0) - ASSERT(false); + int result = pthread_cond_wait(&m_condition, &mutex.impl()); + ASSERT_UNUSED(result, !result); } bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) @@ -256,14 +265,14 @@ bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) void ThreadCondition::signal() { - if (pthread_cond_signal(&m_condition) != 0) - ASSERT(false); + int result = pthread_cond_signal(&m_condition); + ASSERT_UNUSED(result, !result); } void ThreadCondition::broadcast() { - if (pthread_cond_broadcast(&m_condition) != 0) - ASSERT(false); + int result = pthread_cond_broadcast(&m_condition); + ASSERT_UNUSED(result, !result); } } // namespace WTF diff --git a/JavaScriptCore/wtf/ThreadingQt.cpp b/JavaScriptCore/wtf/ThreadingQt.cpp index 55a479b..1fdd2bb 100644 --- a/JavaScriptCore/wtf/ThreadingQt.cpp +++ b/JavaScriptCore/wtf/ThreadingQt.cpp @@ -162,6 +162,10 @@ ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con return establishIdentifierForThread(threadRef); } +void setThreadNameInternal(const char*) +{ +} + int waitForThreadCompletion(ThreadIdentifier threadID, void** result) { ASSERT(threadID); @@ -191,7 +195,7 @@ ThreadIdentifier currentThread() bool isMainThread() { - return currentThread() == mainThreadIdentifier; + return QThread::currentThread() == QCoreApplication::instance()->thread(); } Mutex::Mutex() @@ -242,11 +246,13 @@ bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) if (absoluteTime < currentTime) return false; - double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0; - // Qt defines wait for up to ULONG_MAX milliseconds. - if (intervalMilliseconds >= ULONG_MAX) - intervalMilliseconds = ULONG_MAX; + // Time is too far in the future (and would overflow unsigned long) - wait forever. + if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0) { + wait(mutex); + return true; + } + double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0; return m_condition->wait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds)); } diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp index 399fb38..415ba53 100644 --- a/JavaScriptCore/wtf/ThreadingWin.cpp +++ b/JavaScriptCore/wtf/ThreadingWin.cpp @@ -98,7 +98,7 @@ namespace WTF { -// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadName all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>. +// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>. static const DWORD MS_VC_EXCEPTION = 0x406D1388; #pragma pack(push, 8) @@ -110,16 +110,12 @@ typedef struct tagTHREADNAME_INFO { } THREADNAME_INFO; #pragma pack(pop) -static void setThreadName(DWORD dwThreadID, LPCSTR szThreadName) +void setThreadNameInternal(const char* szThreadName) { - // Visual Studio has a 31-character limit on thread names. Longer names will - // be truncated silently, but we'd like callers to know about the limit. - ASSERT_ARG(szThreadName, strlen(szThreadName) <= 31); - THREADNAME_INFO info; info.dwType = 0x1000; info.szName = szThreadName; - info.dwThreadID = dwThreadID; + info.dwThreadID = GetCurrentThreadId(); info.dwFlags = 0; __try { @@ -157,7 +153,7 @@ void initializeThreading() initializeRandomNumberGenerator(); initializeMainThread(); mainThreadIdentifier = currentThread(); - setThreadName(mainThreadIdentifier, "Main Thread"); + setThreadNameInternal("Main Thread"); } } @@ -220,9 +216,6 @@ ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con return 0; } - if (threadName) - setThreadName(threadIdentifier, threadName); - threadID = static_cast<ThreadIdentifier>(threadIdentifier); storeThreadHandleByIdentifier(threadIdentifier, threadHandle); @@ -457,10 +450,13 @@ bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) if (absoluteTime < currentTime) return false; - double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0; - if (intervalMilliseconds >= INT_MAX) - intervalMilliseconds = INT_MAX; + // Time is too far in the future (and would overflow unsigned long) - wait forever. + if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0) { + wait(mutex); + return true; + } + double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0; return m_condition.timedWait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds)); } diff --git a/JavaScriptCore/wtf/TypeTraits.cpp b/JavaScriptCore/wtf/TypeTraits.cpp new file mode 100644 index 0000000..36fc6c6 --- /dev/null +++ b/JavaScriptCore/wtf/TypeTraits.cpp @@ -0,0 +1,120 @@ + /* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "TypeTraits.h" + +#include "Assertions.h" + +namespace WTF { + +COMPILE_ASSERT(IsInteger<bool>::value, WTF_IsInteger_bool_true); +COMPILE_ASSERT(IsInteger<char>::value, WTF_IsInteger_char_true); +COMPILE_ASSERT(IsInteger<signed char>::value, WTF_IsInteger_signed_char_true); +COMPILE_ASSERT(IsInteger<unsigned char>::value, WTF_IsInteger_unsigned_char_true); +COMPILE_ASSERT(IsInteger<short>::value, WTF_IsInteger_short_true); +COMPILE_ASSERT(IsInteger<unsigned short>::value, WTF_IsInteger_unsigned_short_true); +COMPILE_ASSERT(IsInteger<int>::value, WTF_IsInteger_int_true); +COMPILE_ASSERT(IsInteger<unsigned int>::value, WTF_IsInteger_unsigned_int_true); +COMPILE_ASSERT(IsInteger<long>::value, WTF_IsInteger_long_true); +COMPILE_ASSERT(IsInteger<unsigned long>::value, WTF_IsInteger_unsigned_long_true); +COMPILE_ASSERT(IsInteger<long long>::value, WTF_IsInteger_long_long_true); +COMPILE_ASSERT(IsInteger<unsigned long long>::value, WTF_IsInteger_unsigned_long_long_true); +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) +COMPILE_ASSERT(IsInteger<wchar_t>::value, WTF_IsInteger_wchar_t_true); +#endif +COMPILE_ASSERT(!IsInteger<char*>::value, WTF_IsInteger_char_pointer_false); +COMPILE_ASSERT(!IsInteger<const char*>::value, WTF_IsInteger_const_char_pointer_false); +COMPILE_ASSERT(!IsInteger<volatile char*>::value, WTF_IsInteger_volatile_char_pointer_false); +COMPILE_ASSERT(!IsInteger<double>::value, WTF_IsInteger_double_false); +COMPILE_ASSERT(!IsInteger<float>::value, WTF_IsInteger_float_false); + +COMPILE_ASSERT(IsPod<bool>::value, WTF_IsPod_bool_true); +COMPILE_ASSERT(IsPod<char>::value, WTF_IsPod_char_true); +COMPILE_ASSERT(IsPod<signed char>::value, WTF_IsPod_signed_char_true); +COMPILE_ASSERT(IsPod<unsigned char>::value, WTF_IsPod_unsigned_char_true); +COMPILE_ASSERT(IsPod<short>::value, WTF_IsPod_short_true); +COMPILE_ASSERT(IsPod<unsigned short>::value, WTF_IsPod_unsigned_short_true); +COMPILE_ASSERT(IsPod<int>::value, WTF_IsPod_int_true); +COMPILE_ASSERT(IsPod<unsigned int>::value, WTF_IsPod_unsigned_int_true); +COMPILE_ASSERT(IsPod<long>::value, WTF_IsPod_long_true); +COMPILE_ASSERT(IsPod<unsigned long>::value, WTF_IsPod_unsigned_long_true); +COMPILE_ASSERT(IsPod<long long>::value, WTF_IsPod_long_long_true); +COMPILE_ASSERT(IsPod<unsigned long long>::value, WTF_IsPod_unsigned_long_long_true); +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) +COMPILE_ASSERT(IsPod<wchar_t>::value, WTF_IsPod_wchar_t_true); +#endif +COMPILE_ASSERT(IsPod<char*>::value, WTF_IsPod_char_pointer_true); +COMPILE_ASSERT(IsPod<const char*>::value, WTF_IsPod_const_char_pointer_true); +COMPILE_ASSERT(IsPod<volatile char*>::value, WTF_IsPod_volatile_char_pointer_true); +COMPILE_ASSERT(IsPod<double>::value, WTF_IsPod_double_true); +COMPILE_ASSERT(IsPod<long double>::value, WTF_IsPod_long_double_true); +COMPILE_ASSERT(IsPod<float>::value, WTF_IsPod_float_true); +COMPILE_ASSERT(!IsPod<IsPod<bool> >::value, WTF_IsPod_struct_false); + +enum IsConvertibleToIntegerCheck { }; +COMPILE_ASSERT(IsConvertibleToInteger<IsConvertibleToIntegerCheck>::value, WTF_IsConvertibleToInteger_enum_true); +COMPILE_ASSERT(IsConvertibleToInteger<bool>::value, WTF_IsConvertibleToInteger_bool_true); +COMPILE_ASSERT(IsConvertibleToInteger<char>::value, WTF_IsConvertibleToInteger_char_true); +COMPILE_ASSERT(IsConvertibleToInteger<signed char>::value, WTF_IsConvertibleToInteger_signed_char_true); +COMPILE_ASSERT(IsConvertibleToInteger<unsigned char>::value, WTF_IsConvertibleToInteger_unsigned_char_true); +COMPILE_ASSERT(IsConvertibleToInteger<short>::value, WTF_IsConvertibleToInteger_short_true); +COMPILE_ASSERT(IsConvertibleToInteger<unsigned short>::value, WTF_IsConvertibleToInteger_unsigned_short_true); +COMPILE_ASSERT(IsConvertibleToInteger<int>::value, WTF_IsConvertibleToInteger_int_true); +COMPILE_ASSERT(IsConvertibleToInteger<unsigned int>::value, WTF_IsConvertibleToInteger_unsigned_int_true); +COMPILE_ASSERT(IsConvertibleToInteger<long>::value, WTF_IsConvertibleToInteger_long_true); +COMPILE_ASSERT(IsConvertibleToInteger<unsigned long>::value, WTF_IsConvertibleToInteger_unsigned_long_true); +COMPILE_ASSERT(IsConvertibleToInteger<long long>::value, WTF_IsConvertibleToInteger_long_long_true); +COMPILE_ASSERT(IsConvertibleToInteger<unsigned long long>::value, WTF_IsConvertibleToInteger_unsigned_long_long_true); +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) +COMPILE_ASSERT(IsConvertibleToInteger<wchar_t>::value, WTF_IsConvertibleToInteger_wchar_t_true); +#endif +COMPILE_ASSERT(IsConvertibleToInteger<double>::value, WTF_IsConvertibleToInteger_double_true); +COMPILE_ASSERT(IsConvertibleToInteger<long double>::value, WTF_IsConvertibleToInteger_long_double_true); +COMPILE_ASSERT(IsConvertibleToInteger<float>::value, WTF_IsConvertibleToInteger_float_true); +COMPILE_ASSERT(!IsConvertibleToInteger<char*>::value, WTF_IsConvertibleToInteger_char_pointer_false); +COMPILE_ASSERT(!IsConvertibleToInteger<const char*>::value, WTF_IsConvertibleToInteger_const_char_pointer_false); +COMPILE_ASSERT(!IsConvertibleToInteger<volatile char*>::value, WTF_IsConvertibleToInteger_volatile_char_pointer_false); +COMPILE_ASSERT(!IsConvertibleToInteger<IsConvertibleToInteger<bool> >::value, WTF_IsConvertibleToInteger_struct_false); + +COMPILE_ASSERT((IsSameType<bool, bool>::value), WTF_IsSameType_bool_true); +COMPILE_ASSERT((IsSameType<int*, int*>::value), WTF_IsSameType_int_pointer_true); +COMPILE_ASSERT((!IsSameType<int, int*>::value), WTF_IsSameType_int_int_pointer_false); +COMPILE_ASSERT((!IsSameType<bool, const bool>::value), WTF_IsSameType_const_change_false); +COMPILE_ASSERT((!IsSameType<bool, volatile bool>::value), WTF_IsSameType_volatile_change_false); + +COMPILE_ASSERT((IsSameType<bool, RemoveConst<const bool>::Type>::value), WTF_test_RemoveConst_const_bool); +COMPILE_ASSERT((!IsSameType<bool, RemoveConst<volatile bool>::Type>::value), WTF_test_RemoveConst_volatile_bool); + +COMPILE_ASSERT((IsSameType<bool, RemoveVolatile<bool>::Type>::value), WTF_test_RemoveVolatile_bool); +COMPILE_ASSERT((!IsSameType<bool, RemoveVolatile<const bool>::Type>::value), WTF_test_RemoveVolatile_const_bool); +COMPILE_ASSERT((IsSameType<bool, RemoveVolatile<volatile bool>::Type>::value), WTF_test_RemoveVolatile_volatile_bool); + +COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<bool>::Type>::value), WTF_test_RemoveConstVolatile_bool); +COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<const bool>::Type>::value), WTF_test_RemoveConstVolatile_const_bool); +COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<volatile bool>::Type>::value), WTF_test_RemoveConstVolatile_volatile_bool); +COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<const volatile bool>::Type>::value), WTF_test_RemoveConstVolatile_const_volatile_bool); + +COMPILE_ASSERT((IsSameType<int, RemovePointer<int>::Type>::value), WTF_Test_RemovePointer_int); +COMPILE_ASSERT((IsSameType<int, RemovePointer<int*>::Type>::value), WTF_Test_RemovePointer_int_pointer); +COMPILE_ASSERT((!IsSameType<int, RemovePointer<int**>::Type>::value), WTF_Test_RemovePointer_int_pointer_pointer); + +} // namespace WTF diff --git a/JavaScriptCore/wtf/TypeTraits.h b/JavaScriptCore/wtf/TypeTraits.h new file mode 100644 index 0000000..2aeabcf --- /dev/null +++ b/JavaScriptCore/wtf/TypeTraits.h @@ -0,0 +1,133 @@ + /* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TypeTraits_h +#define TypeTraits_h + +#include "Platform.h" + +namespace WTF { + + // The following are provided in this file: + // + // IsInteger<T>::value + // IsPod<T>::value, see the definition for a note about its limitations + // IsConvertibleToInteger<T>::value + // + // IsSameType<T, U>::value + // + // RemovePointer<T>::Type + // RemoveConst<T>::Type + // RemoveVolatile<T>::Type + // RemoveConstVolatile<T>::Type + // + // COMPILE_ASSERT's in TypeTraits.cpp illustrate their usage and what they do. + + template<typename T> struct IsInteger { static const bool value = false; }; + template<> struct IsInteger<bool> { static const bool value = true; }; + template<> struct IsInteger<char> { static const bool value = true; }; + template<> struct IsInteger<signed char> { static const bool value = true; }; + template<> struct IsInteger<unsigned char> { static const bool value = true; }; + template<> struct IsInteger<short> { static const bool value = true; }; + template<> struct IsInteger<unsigned short> { static const bool value = true; }; + template<> struct IsInteger<int> { static const bool value = true; }; + template<> struct IsInteger<unsigned int> { static const bool value = true; }; + template<> struct IsInteger<long> { static const bool value = true; }; + template<> struct IsInteger<unsigned long> { static const bool value = true; }; + template<> struct IsInteger<long long> { static const bool value = true; }; + template<> struct IsInteger<unsigned long long> { static const bool value = true; }; +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) + template<> struct IsInteger<wchar_t> { static const bool value = true; }; +#endif + + // IsPod is misnamed as it doesn't cover all plain old data (pod) types. + // Specifically, it doesn't allow for enums or for structs. + template <typename T> struct IsPod { static const bool value = IsInteger<T>::value; }; + template <> struct IsPod<float> { static const bool value = true; }; + template <> struct IsPod<double> { static const bool value = true; }; + template <> struct IsPod<long double> { static const bool value = true; }; + template <typename P> struct IsPod<P*> { static const bool value = true; }; + + template<typename T> class IsConvertibleToInteger { + // Avoid "possible loss of data" warning when using Microsoft's C++ compiler + // by not converting int's to doubles. + template<bool performCheck, typename U> class IsConvertibleToDouble; + template<typename U> class IsConvertibleToDouble<false, U> { + public: + static const bool value = false; + }; + + template<typename U> class IsConvertibleToDouble<true, U> { + typedef char YesType; + struct NoType { + char padding[8]; + }; + + static YesType floatCheck(long double); + static NoType floatCheck(...); + static T& t; + public: + static const bool value = sizeof(floatCheck(t)) == sizeof(YesType); + }; + + public: + static const bool value = IsInteger<T>::value || IsConvertibleToDouble<!IsInteger<T>::value, T>::value; + }; + + template <typename T, typename U> struct IsSameType { + static const bool value = false; + }; + + template <typename T> struct IsSameType<T, T> { + static const bool value = true; + }; + + template <typename T> struct RemoveConst { + typedef T Type; + }; + + template <typename T> struct RemoveConst<const T> { + typedef T Type; + }; + + template <typename T> struct RemoveVolatile { + typedef T Type; + }; + + template <typename T> struct RemoveVolatile<volatile T> { + typedef T Type; + }; + + template <typename T> struct RemoveConstVolatile { + typedef typename RemoveVolatile<typename RemoveConst<T>::Type>::Type Type; + }; + + template <typename T> struct RemovePointer { + typedef T Type; + }; + + template <typename T> struct RemovePointer<T*> { + typedef T Type; + }; + +} // namespace WTF + +#endif // TypeTraits_h diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 880b45d..190226d 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -377,7 +377,8 @@ namespace WTF { VectorBuffer(size_t capacity) : Base(inlineBuffer(), inlineCapacity) { - allocateBuffer(capacity); + if (capacity > inlineCapacity) + Base::allocateBuffer(capacity); } ~VectorBuffer() @@ -389,6 +390,10 @@ namespace WTF { { if (newCapacity > inlineCapacity) Base::allocateBuffer(newCapacity); + else { + m_buffer = inlineBuffer(); + m_capacity = inlineCapacity; + } } void deallocateBuffer(T* bufferToDeallocate) @@ -503,6 +508,7 @@ namespace WTF { void grow(size_t size); void resize(size_t size); void reserveCapacity(size_t newCapacity); + void reserveInitialCapacity(size_t initialCapacity); void shrinkCapacity(size_t newCapacity); void shrinkToFit() { shrinkCapacity(size()); } @@ -733,6 +739,15 @@ namespace WTF { } template<typename T, size_t inlineCapacity> + inline void Vector<T, inlineCapacity>::reserveInitialCapacity(size_t initialCapacity) + { + ASSERT(!m_size); + ASSERT(capacity() == inlineCapacity); + if (initialCapacity > inlineCapacity) + m_buffer.allocateBuffer(initialCapacity); + } + + template<typename T, size_t inlineCapacity> void Vector<T, inlineCapacity>::shrinkCapacity(size_t newCapacity) { if (newCapacity >= capacity()) diff --git a/JavaScriptCore/wtf/VectorTraits.h b/JavaScriptCore/wtf/VectorTraits.h index 6efe36c..7974b9a 100644 --- a/JavaScriptCore/wtf/VectorTraits.h +++ b/JavaScriptCore/wtf/VectorTraits.h @@ -22,6 +22,7 @@ #define WTF_VectorTraits_h #include "RefPtr.h" +#include "TypeTraits.h" #include <utility> #include <memory> @@ -29,24 +30,6 @@ using std::pair; namespace WTF { - template <typename T> struct IsPod { static const bool value = false; }; - template <> struct IsPod<bool> { static const bool value = true; }; - template <> struct IsPod<char> { static const bool value = true; }; - template <> struct IsPod<signed char> { static const bool value = true; }; - template <> struct IsPod<unsigned char> { static const bool value = true; }; - template <> struct IsPod<short> { static const bool value = true; }; - template <> struct IsPod<unsigned short> { static const bool value = true; }; - template <> struct IsPod<int> { static const bool value = true; }; - template <> struct IsPod<unsigned int> { static const bool value = true; }; - template <> struct IsPod<long> { static const bool value = true; }; - template <> struct IsPod<unsigned long> { static const bool value = true; }; - template <> struct IsPod<long long> { static const bool value = true; }; - template <> struct IsPod<unsigned long long> { static const bool value = true; }; - template <> struct IsPod<float> { static const bool value = true; }; - template <> struct IsPod<double> { static const bool value = true; }; - template <> struct IsPod<long double> { static const bool value = true; }; - template <typename P> struct IsPod<P *> { static const bool value = true; }; - template<bool isPod, typename T> class VectorTraitsBase; diff --git a/JavaScriptCore/wtf/android/MainThreadAndroid.cpp b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp index d00c0ab..ab0d3bf 100644 --- a/JavaScriptCore/wtf/android/MainThreadAndroid.cpp +++ b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp @@ -38,6 +38,10 @@ static void timeoutFired(void* ) dispatchFunctionsFromMainThread(); } +void initializeMainThreadPlatform() +{ +} + void scheduleDispatchFunctionsOnMainThread() { JavaSharedClient::EnqueueFunctionPtr(timeoutFired, 0); diff --git a/JavaScriptCore/wtf/chromium/ChromiumThreading.h b/JavaScriptCore/wtf/chromium/ChromiumThreading.h new file mode 100644 index 0000000..e9b1f39 --- /dev/null +++ b/JavaScriptCore/wtf/chromium/ChromiumThreading.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) 2009 Google 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: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * 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. +* * Neither the name of Google Inc. nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "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 THE COPYRIGHT +* OWNER 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 ChromiumThreading_h +#define ChromiumThreading_h + +namespace WTF { + + // An interface to the embedding layer, which provides threading support. + class ChromiumThreading { + public: + static void initializeMainThread(); + static void scheduleDispatchFunctionsOnMainThread(); + }; + +} // namespace WTF + +#endif // ChromiumThreading_h diff --git a/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp new file mode 100644 index 0000000..394370f --- /dev/null +++ b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2009 Google 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: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * 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. +* * Neither the name of Google Inc. nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "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 THE COPYRIGHT +* OWNER 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 "MainThread.h" + +#include "ChromiumThreading.h" + +namespace WTF { + +void initializeMainThreadPlatform() +{ + ChromiumThreading::initializeMainThread(); +} + +void scheduleDispatchFunctionsOnMainThread() +{ + ChromiumThreading::scheduleDispatchFunctionsOnMainThread(); +} + +} // namespace WTF + diff --git a/JavaScriptCore/wtf/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp index c9e8d30..c104dad 100644 --- a/JavaScriptCore/wtf/dtoa.cpp +++ b/JavaScriptCore/wtf/dtoa.cpp @@ -824,16 +824,16 @@ static double b2d(Bigint* a, int* e) *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { - d0 = Exp_1 | y >> Ebits - k; + d0 = Exp_1 | (y >> (Ebits - k)); w = xa > xa0 ? *--xa : 0; - d1 = y << (32 - Ebits) + k | w >> Ebits - k; + d1 = (y << (32 - Ebits + k)) | (w >> (Ebits - k)); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> 32 - k; + d0 = Exp_1 | (y << k) | (z >> (32 - k)); y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> 32 - k; + d1 = (z << k) | (y >> (32 - k)); } else { d0 = Exp_1 | y; d1 = z; @@ -889,7 +889,7 @@ static Bigint* d2b(double d, int* e, int* bits) #ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(&y))) { - x[0] = y | z << 32 - k; + x[0] = y | (z << (32 - k)); z >>= k; } else x[0] = y; @@ -1349,7 +1349,7 @@ ovfl: if (j >= 53) word0(rv) = (P + 2) * Exp_msk1; else - word0(rv) &= 0xffffffff << j - 32; + word0(rv) &= 0xffffffff << (j - 32); } else word1(rv) &= 0xffffffff << j; } @@ -2011,8 +2011,8 @@ char* dtoa(double d, int ndigits, int* decpt, int* sign, char** rve) /* d is denormalized */ i = bbits + be + (Bias + (P - 1) - 1); - x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 - : word1(d) << 32 - i; + x = (i > 32) ? (word0(d) << (64 - i)) | (word1(d) >> (i - 32)) + : word1(d) << (32 - i); dval(d2) = x; word0(d2) -= 31 * Exp_msk1; /* adjust exponent */ i -= (Bias + (P - 1) - 1) + 1; @@ -2193,7 +2193,7 @@ fast_failed: } if (i == ilim) { dval(d) += dval(d); - if (dval(d) > ds || dval(d) == ds && L & 1) { + if (dval(d) > ds || (dval(d) == ds && (L & 1))) { bump_up: while (*--s == '9') if (s == s0) { @@ -2334,7 +2334,7 @@ bump_up: *s++ = dig; goto ret; } - if (j < 0 || j == 0 && !(word1(d) & 1)) { + if (j < 0 || (j == 0 && !(word1(d) & 1))) { if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; @@ -2344,7 +2344,7 @@ bump_up: if (j1 > 0) { b = lshift(b, 1); j1 = cmp(b, S); - if ((j1 > 0 || j1 == 0 && dig & 1) && dig++ == '9') + if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') goto round_9_up; } accept_dig: @@ -2389,7 +2389,7 @@ round_9_up: b = lshift(b, 1); j = cmp(b, S); - if (j > 0 || j == 0 && dig & 1) { + if (j > 0 || (j == 0 && (dig & 1))) { roundoff: while (*--s == '9') if (s == s0) { diff --git a/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp b/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp index a6e061f..7624247 100644 --- a/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp +++ b/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp @@ -34,6 +34,10 @@ namespace WTF { +void initializeMainThreadPlatform() +{ +} + static gboolean timeoutFired(gpointer) { dispatchFunctionsFromMainThread(); @@ -45,5 +49,4 @@ void scheduleDispatchFunctionsOnMainThread() g_timeout_add(0, timeoutFired, 0); } - -} +} // namespace WTF diff --git a/JavaScriptCore/wtf/mac/MainThreadMac.mm b/JavaScriptCore/wtf/mac/MainThreadMac.mm index b04ef0e..c79acc1 100644 --- a/JavaScriptCore/wtf/mac/MainThreadMac.mm +++ b/JavaScriptCore/wtf/mac/MainThreadMac.mm @@ -30,6 +30,7 @@ #import "MainThread.h" #import <Foundation/NSThread.h> +#import <wtf/Assertions.h> @interface WTFMainThreadCaller : NSObject { } @@ -47,11 +48,18 @@ namespace WTF { +static WTFMainThreadCaller* staticMainThreadCaller = nil; + +void initializeMainThreadPlatform() +{ + ASSERT(!staticMainThreadCaller); + staticMainThreadCaller = [[WTFMainThreadCaller alloc] init]; +} + void scheduleDispatchFunctionsOnMainThread() { - WTFMainThreadCaller *caller = [[WTFMainThreadCaller alloc] init]; - [caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; - [caller release]; + ASSERT(staticMainThreadCaller); + [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; } } // namespace WTF diff --git a/JavaScriptCore/wtf/qt/MainThreadQt.cpp b/JavaScriptCore/wtf/qt/MainThreadQt.cpp index 1914600..7b2d0f2 100644 --- a/JavaScriptCore/wtf/qt/MainThreadQt.cpp +++ b/JavaScriptCore/wtf/qt/MainThreadQt.cpp @@ -58,12 +58,15 @@ void MainThreadInvoker::dispatch() Q_GLOBAL_STATIC(MainThreadInvoker, webkit_main_thread_invoker) +void initializeMainThreadPlatform() +{ +} void scheduleDispatchFunctionsOnMainThread() { QMetaObject::invokeMethod(webkit_main_thread_invoker(), "dispatch", Qt::QueuedConnection); } -} +} // namespace WTF #include "MainThreadQt.moc" diff --git a/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h index 608aea6..de5e082 100644 --- a/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h +++ b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h @@ -179,6 +179,11 @@ inline bool isPunct(UChar32 c) return !!u_ispunct(c); } +inline bool hasLineBreakingPropertyComplexContext(UChar32 c) +{ + return u_getIntPropertyValue(c, UCHAR_LINE_BREAK) == U_LB_COMPLEX_CONTEXT; +} + inline UChar32 mirroredChar(UChar32 c) { return u_charMirror(c); diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index d7d78ce..f65e292 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -352,6 +352,12 @@ inline bool isLower(UChar32 c) return QChar::category(c) == QChar::Letter_Lowercase; } +inline bool hasLineBreakingPropertyComplexContext(UChar32) +{ + // FIXME: Implement this to return whether the character has line breaking property SA (Complex Context). + return false; +} + inline UChar32 mirroredChar(UChar32 c) { return QChar::mirroredChar(c); diff --git a/JavaScriptCore/wtf/win/MainThreadWin.cpp b/JavaScriptCore/wtf/win/MainThreadWin.cpp index 5f0163c..b828b7d 100644 --- a/JavaScriptCore/wtf/win/MainThreadWin.cpp +++ b/JavaScriptCore/wtf/win/MainThreadWin.cpp @@ -50,13 +50,11 @@ LRESULT CALLBACK ThreadingWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, return 0; } -void initializeMainThread() +void initializeMainThreadPlatform() { if (threadingWindowHandle) return; - mainThreadFunctionQueueMutex(); - WNDCLASSEX wcex; memset(&wcex, 0, sizeof(WNDCLASSEX)); wcex.cbSize = sizeof(WNDCLASSEX); @@ -75,4 +73,4 @@ void scheduleDispatchFunctionsOnMainThread() PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0); } -} // namespace WebCore +} // namespace WTF diff --git a/JavaScriptCore/wtf/wx/MainThreadWx.cpp b/JavaScriptCore/wtf/wx/MainThreadWx.cpp index 3166331..bcd5f05 100644 --- a/JavaScriptCore/wtf/wx/MainThreadWx.cpp +++ b/JavaScriptCore/wtf/wx/MainThreadWx.cpp @@ -31,8 +31,12 @@ namespace WTF { -void scheduleDispatchFunctionsOnMainThread() +void initializeMainThreadPlatform() { } +void scheduleDispatchFunctionsOnMainThread() +{ } + +} // namespace WTF |