diff options
Diffstat (limited to 'JavaScriptCore/wtf')
80 files changed, 6620 insertions, 836 deletions
diff --git a/JavaScriptCore/wtf/ASCIICType.h b/JavaScriptCore/wtf/ASCIICType.h index 0c3c29f..b43bb37 100644 --- a/JavaScriptCore/wtf/ASCIICType.h +++ b/JavaScriptCore/wtf/ASCIICType.h @@ -30,7 +30,6 @@ #define WTF_ASCIICType_h #include <wtf/Assertions.h> -#include <wtf/Platform.h> // The behavior of many of the functions in the <ctype.h> header is dependent // on the current locale. But in the WebKit project, all uses of those functions diff --git a/JavaScriptCore/wtf/AlwaysInline.h b/JavaScriptCore/wtf/AlwaysInline.h index 4e7224c..34f8b74 100644 --- a/JavaScriptCore/wtf/AlwaysInline.h +++ b/JavaScriptCore/wtf/AlwaysInline.h @@ -33,6 +33,8 @@ #ifndef NEVER_INLINE #if COMPILER(GCC) #define NEVER_INLINE __attribute__((__noinline__)) +#elif COMPILER(RVCT) +#define NEVER_INLINE __declspec(noinline) #else #define NEVER_INLINE #endif @@ -57,7 +59,17 @@ #ifndef NO_RETURN #if COMPILER(GCC) #define NO_RETURN __attribute((__noreturn__)) +#elif COMPILER(MSVC) || COMPILER(RVCT) +#define NO_RETURN __declspec(noreturn) #else #define NO_RETURN #endif #endif + +#ifndef NO_RETURN_WITH_VALUE +#if !COMPILER(MSVC) +#define NO_RETURN_WITH_VALUE NO_RETURN +#else +#define NO_RETURN_WITH_VALUE +#endif +#endif diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index 0e02af5..d26b939 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -56,12 +56,13 @@ #endif #ifdef NDEBUG +/* Disable ASSERT* macros in release mode. */ #define ASSERTIONS_DISABLED_DEFAULT 1 #else #define ASSERTIONS_DISABLED_DEFAULT 0 #endif -#if COMPILER(MSVC7) || COMPILER(WINSCW) +#if COMPILER(MSVC7_OR_LOWER) || COMPILER(WINSCW) #define HAVE_VARIADIC_MACRO 0 #else #define HAVE_VARIADIC_MACRO 1 @@ -148,8 +149,14 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann } #endif -/* CRASH -- gets us into the debugger or the crash reporter -- signals are ignored by the crash reporter so we must do better */ +/* CRASH() - Raises a fatal error resulting in program termination and triggering either the debugger or the crash reporter. + Use CRASH() in response to known, unrecoverable errors like out-of-memory. + Macro is enabled in both debug and release mode. + To test for unknown errors and verify assumptions, use ASSERT instead, to avoid impacting performance in release builds. + + Signals are ignored by the crash reporter on OS X so we must do better. +*/ #ifndef CRASH #if OS(SYMBIAN) #define CRASH() do { \ @@ -164,7 +171,11 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann #endif #endif -/* ASSERT, ASSERT_NOT_REACHED, ASSERT_UNUSED */ +/* ASSERT, ASSERT_NOT_REACHED, ASSERT_UNUSED + + These macros are compiled out of release builds. + Expressions inside them are evaluated in debug builds only. +*/ #if OS(WINCE) && !PLATFORM(TORCHMOBILE) /* FIXME: We include this here only to avoid a conflict with the ASSERT macro. */ @@ -213,7 +224,7 @@ while (0) /* ASSERT_WITH_MESSAGE */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define ASSERT_WITH_MESSAGE(assertion) ((void)0) #elif COMPILER(WINSCW) #define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) @@ -253,7 +264,7 @@ while (0) /* FATAL */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define FATAL() ((void)0) #elif COMPILER(WINSCW) #define FATAL(arg...) ((void)0) @@ -268,7 +279,7 @@ while (0) /* LOG_ERROR */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG_ERROR() ((void)0) #elif COMPILER(WINSCW) #define LOG_ERROR(arg...) ((void)0) @@ -280,7 +291,7 @@ while (0) /* LOG */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG() ((void)0) #elif COMPILER(WINSCW) #define LOG(arg...) ((void)0) @@ -294,7 +305,7 @@ while (0) /* LOG_VERBOSE */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG_VERBOSE(channel) ((void)0) #elif COMPILER(WINSCW) #define LOG_VERBOSE(channel, arg...) ((void)0) diff --git a/JavaScriptCore/wtf/Atomics.h b/JavaScriptCore/wtf/Atomics.h new file mode 100644 index 0000000..1d190a3 --- /dev/null +++ b/JavaScriptCore/wtf/Atomics.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + * + * + * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based + * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license + * is virtually identical to the Apple license above but is included here for completeness. + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef Atomics_h +#define Atomics_h + +#include "Platform.h" + +#if OS(WINDOWS) +#include <windows.h> +#elif OS(DARWIN) +#include <libkern/OSAtomic.h> +#elif OS(ANDROID) +#include <cutils/atomic.h> +#elif COMPILER(GCC) && !OS(SYMBIAN) +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) +#include <ext/atomicity.h> +#else +#include <bits/atomicity.h> +#endif +#endif + +namespace WTF { + +#if OS(WINDOWS) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +#if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE) +inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } +inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } +#else +inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } +#endif + +#elif OS(DARWIN) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } + +#elif OS(ANDROID) + +inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } +inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } + +#elif COMPILER(GCC) && !CPU(SPARC64) && !OS(SYMBIAN) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } +inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } + +#endif + +} // namespace WTF + +#if USE(LOCKFREE_THREADSAFESHARED) +using WTF::atomicDecrement; +using WTF::atomicIncrement; +#endif + +#endif // Atomics_h diff --git a/JavaScriptCore/wtf/CurrentTime.cpp b/JavaScriptCore/wtf/CurrentTime.cpp index 30ca7c3..08fffa2 100644 --- a/JavaScriptCore/wtf/CurrentTime.cpp +++ b/JavaScriptCore/wtf/CurrentTime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008 Google Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * @@ -53,15 +53,13 @@ extern "C" time_t mktime(struct tm *t); #endif #endif -#elif PLATFORM(CF) -#include <CoreFoundation/CFDate.h> #elif PLATFORM(GTK) #include <glib.h> #elif PLATFORM(WX) #include <wx/datetime.h> #elif PLATFORM(BREWMP) #include <AEEStdLib.h> -#else // Posix systems relying on the gettimeofday() +#else #include <sys/time.h> #endif @@ -251,13 +249,6 @@ double currentTime() #endif // USE(QUERY_PERFORMANCE_COUNTER) -#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 @@ -293,15 +284,13 @@ double currentTime() return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond)); } -#else // Other Posix systems rely on the gettimeofday(). +#else double currentTime() { struct timeval now; - struct timezone zone; - - gettimeofday(&now, &zone); - return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0); + gettimeofday(&now, 0); + return now.tv_sec + now.tv_usec / 1000000.0; } #endif diff --git a/JavaScriptCore/wtf/CurrentTime.h b/JavaScriptCore/wtf/CurrentTime.h index 033448f..dcb1f6c 100644 --- a/JavaScriptCore/wtf/CurrentTime.h +++ b/JavaScriptCore/wtf/CurrentTime.h @@ -49,7 +49,7 @@ namespace WTF { inline void getLocalTime(const time_t* localTime, struct tm* localTM) { - #if COMPILER(MSVC7) || COMPILER(MINGW) || OS(WINCE) + #if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE) *localTM = *localtime(localTime); #elif COMPILER(MSVC) localtime_s(localTM, localTime); diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 79d2bfb..9dfbc6b 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -204,6 +204,16 @@ TryMallocReturnValue tryFastZeroedMalloc(size_t n) #if FORCE_SYSTEM_MALLOC +#if PLATFORM(BREWMP) +#include "brew/SystemMallocBrew.h" +#endif + +#if OS(DARWIN) +#include <malloc/malloc.h> +#elif COMPILER(MSVC) +#include <malloc.h> +#endif + namespace WTF { TryMallocReturnValue tryFastMalloc(size_t n) @@ -365,10 +375,21 @@ void releaseFastMallocFreeMemory() { } FastMallocStatistics fastMallocStatistics() { - FastMallocStatistics statistics = { 0, 0, 0, 0 }; + FastMallocStatistics statistics = { 0, 0, 0 }; return statistics; } +size_t fastMallocSize(const void* p) +{ +#if OS(DARWIN) + return malloc_size(p); +#elif COMPILER(MSVC) + return _msize(const_cast<void*>(p)); +#else + return 1; +#endif +} + } // namespace WTF #if OS(DARWIN) @@ -396,7 +417,6 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #include <algorithm> #include <errno.h> #include <limits> -#include <new> #include <pthread.h> #include <stdarg.h> #include <stddef.h> @@ -411,7 +431,7 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #include <windows.h> #endif -#if WTF_CHANGES +#ifdef WTF_CHANGES #if OS(DARWIN) #include "MallocZoneSupport.h" @@ -460,7 +480,7 @@ namespace WTF { #define CHECK_CONDITION ASSERT #if OS(DARWIN) -class Span; +struct Span; class TCMalloc_Central_FreeListPadded; class TCMalloc_PageHeap; class TCMalloc_ThreadCache; @@ -1232,29 +1252,34 @@ template <> class MapSelector<32> { // ------------------------------------------------------------------------- #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY -// The central page heap collects spans of memory that have been deleted but are still committed until they are released -// back to the system. We use a background thread to periodically scan the list of free spans and release some back to the -// system. Every 5 seconds, the background thread wakes up and does the following: -// - Check if we needed to commit memory in the last 5 seconds. If so, skip this scavenge because it's a sign that we are short -// of free committed pages and so we should not release them back to the system yet. -// - Otherwise, go through the list of free spans (from largest to smallest) and release up to a fraction of the free committed pages -// back to the system. -// - If the number of free committed pages reaches kMinimumFreeCommittedPageCount, we can stop the scavenging and block the -// scavenging thread until the number of free committed pages goes above kMinimumFreeCommittedPageCount. - -// Background thread wakes up every 5 seconds to scavenge as long as there is memory available to return to the system. -static const int kScavengeTimerDelayInSeconds = 5; - -// Number of free committed pages that we want to keep around. -static const size_t kMinimumFreeCommittedPageCount = 512; - -// During a scavenge, we'll release up to a fraction of the free committed pages. -#if OS(WINDOWS) -// We are slightly less aggressive in releasing memory on Windows due to performance reasons. -static const int kMaxScavengeAmountFactor = 3; -#else -static const int kMaxScavengeAmountFactor = 2; -#endif +// The page heap maintains a free list for spans that are no longer in use by +// the central cache or any thread caches. We use a background thread to +// periodically scan the free list and release a percentage of it back to the OS. + +// If free_committed_pages_ exceeds kMinimumFreeCommittedPageCount, the +// background thread: +// - wakes up +// - pauses for kScavengeDelayInSeconds +// - returns to the OS a percentage of the memory that remained unused during +// that pause (kScavengePercentage * min_free_committed_pages_since_last_scavenge_) +// The goal of this strategy is to reduce memory pressure in a timely fashion +// while avoiding thrashing the OS allocator. + +// Time delay before the page heap scavenger will consider returning pages to +// the OS. +static const int kScavengeDelayInSeconds = 2; + +// Approximate percentage of free committed pages to return to the OS in one +// scavenge. +static const float kScavengePercentage = .5f; + +// number of span lists to keep spans in when memory is returned. +static const int kMinSpanListsWithSpans = 32; + +// Number of free committed pages that we want to keep around. The minimum number of pages used when there +// is 1 span in each of the first kMinSpanListsWithSpans spanlists. Currently 528 pages. +static const size_t kMinimumFreeCommittedPageCount = kMinSpanListsWithSpans * ((1.0f+kMinSpanListsWithSpans) / 2.0f); + #endif class TCMalloc_PageHeap { @@ -1360,8 +1385,9 @@ class TCMalloc_PageHeap { // Number of pages kept in free lists that are still committed. Length free_committed_pages_; - // Number of pages that we committed in the last scavenge wait interval. - Length pages_committed_since_last_scavenge_; + // Minimum number of free committed pages since last scavenge. (Can be 0 if + // we've committed new pages since the last scavenge.) + Length min_free_committed_pages_since_last_scavenge_; #endif bool GrowHeap(Length n); @@ -1406,13 +1432,13 @@ class TCMalloc_PageHeap { void initializeScavenger(); ALWAYS_INLINE void signalScavenger(); void scavenge(); - ALWAYS_INLINE bool shouldContinueScavenging() const; + ALWAYS_INLINE bool shouldScavenge() const; #if !HAVE(DISPATCH_H) - static NO_RETURN void* runScavengerThread(void*); + static NO_RETURN_WITH_VALUE void* runScavengerThread(void*); NO_RETURN void scavengerThread(); - // Keeps track of whether the background thread is actively scavenging memory every kScavengeTimerDelayInSeconds, or + // Keeps track of whether the background thread is actively scavenging memory every kScavengeDelayInSeconds, or // it's blocked waiting for more pages to be deleted. bool m_scavengeThreadActive; @@ -1438,7 +1464,7 @@ void TCMalloc_PageHeap::init() #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY free_committed_pages_ = 0; - pages_committed_since_last_scavenge_ = 0; + min_free_committed_pages_since_last_scavenge_ = 0; #endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY scavenge_counter_ = 0; @@ -1481,7 +1507,7 @@ void* TCMalloc_PageHeap::runScavengerThread(void* context) ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger() { - if (!m_scavengeThreadActive && shouldContinueScavenging()) + if (!m_scavengeThreadActive && shouldScavenge()) pthread_cond_signal(&m_scavengeCondition); } @@ -1491,15 +1517,15 @@ void TCMalloc_PageHeap::initializeScavenger() { m_scavengeQueue = dispatch_queue_create("com.apple.JavaScriptCore.FastMallocSavenger", NULL); m_scavengeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_scavengeQueue); - dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, kScavengeTimerDelayInSeconds * NSEC_PER_SEC); - dispatch_source_set_timer(m_scavengeTimer, startTime, kScavengeTimerDelayInSeconds * NSEC_PER_SEC, 1000 * NSEC_PER_USEC); + dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, kScavengeDelayInSeconds * NSEC_PER_SEC); + dispatch_source_set_timer(m_scavengeTimer, startTime, kScavengeDelayInSeconds * NSEC_PER_SEC, 1000 * NSEC_PER_USEC); dispatch_source_set_event_handler(m_scavengeTimer, ^{ periodicScavenge(); }); m_scavengingScheduled = false; } ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger() { - if (!m_scavengingScheduled && shouldContinueScavenging()) { + if (!m_scavengingScheduled && shouldScavenge()) { m_scavengingScheduled = true; dispatch_resume(m_scavengeTimer); } @@ -1507,42 +1533,37 @@ ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger() #endif -void TCMalloc_PageHeap::scavenge() +void TCMalloc_PageHeap::scavenge() { - // If we have to commit memory in the last 5 seconds, it means we don't have enough free committed pages - // for the amount of allocations that we do. So hold off on releasing memory back to the system. - if (pages_committed_since_last_scavenge_ > 0) { - pages_committed_since_last_scavenge_ = 0; - return; - } - Length pagesDecommitted = 0; - for (int i = kMaxPages; i >= 0; i--) { - SpanList* slist = (static_cast<size_t>(i) == kMaxPages) ? &large_ : &free_[i]; - if (!DLL_IsEmpty(&slist->normal)) { - // Release the last span on the normal portion of this list - Span* s = slist->normal.prev; - // Only decommit up to a fraction of the free committed pages if pages_allocated_since_last_scavenge_ > 0. - if ((pagesDecommitted + s->length) * kMaxScavengeAmountFactor > free_committed_pages_) - continue; - DLL_Remove(s); - TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift), - static_cast<size_t>(s->length << kPageShift)); - if (!s->decommitted) { - pagesDecommitted += s->length; - s->decommitted = true; + size_t pagesToRelease = min_free_committed_pages_since_last_scavenge_ * kScavengePercentage; + size_t targetPageCount = std::max<size_t>(kMinimumFreeCommittedPageCount, free_committed_pages_ - pagesToRelease); + + while (free_committed_pages_ > targetPageCount) { + for (int i = kMaxPages; i > 0 && free_committed_pages_ >= targetPageCount; i--) { + SpanList* slist = (static_cast<size_t>(i) == kMaxPages) ? &large_ : &free_[i]; + // If the span size is bigger than kMinSpanListsWithSpans pages return all the spans in the list, else return all but 1 span. + // Return only 50% of a spanlist at a time so spans of size 1 are not the only ones left. + size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? DLL_Length(&slist->normal) : static_cast<size_t>(.5 * DLL_Length(&slist->normal)); + for (int j = 0; static_cast<size_t>(j) < numSpansToReturn && !DLL_IsEmpty(&slist->normal) && free_committed_pages_ > targetPageCount; j++) { + Span* s = slist->normal.prev; + DLL_Remove(s); + ASSERT(!s->decommitted); + if (!s->decommitted) { + TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift), + static_cast<size_t>(s->length << kPageShift)); + ASSERT(free_committed_pages_ >= s->length); + free_committed_pages_ -= s->length; + s->decommitted = true; + } + DLL_Prepend(&slist->returned, s); } - DLL_Prepend(&slist->returned, s); - // We can stop scavenging if the number of free committed pages left is less than or equal to the minimum number we want to keep around. - if (free_committed_pages_ <= kMinimumFreeCommittedPageCount + pagesDecommitted) - break; } } - pages_committed_since_last_scavenge_ = 0; - ASSERT(free_committed_pages_ >= pagesDecommitted); - free_committed_pages_ -= pagesDecommitted; + + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; } -ALWAYS_INLINE bool TCMalloc_PageHeap::shouldContinueScavenging() const +ALWAYS_INLINE bool TCMalloc_PageHeap::shouldScavenge() const { return free_committed_pages_ > kMinimumFreeCommittedPageCount; } @@ -1571,20 +1592,13 @@ inline Span* TCMalloc_PageHeap::New(Length n) { Span* result = ll->next; Carve(result, n, released); - if (result->decommitted) { - TCMalloc_SystemCommit(reinterpret_cast<void*>(result->start << kPageShift), static_cast<size_t>(n << kPageShift)); - result->decommitted = false; -#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - pages_committed_since_last_scavenge_ += n; -#endif - } #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - else { - // The newly allocated memory is from a span that's in the normal span list (already committed). Update the - // free committed pages count. - ASSERT(free_committed_pages_ >= n); - free_committed_pages_ -= n; - } + // The newly allocated memory is from a span that's in the normal span list (already committed). Update the + // free committed pages count. + ASSERT(free_committed_pages_ >= n); + free_committed_pages_ -= n; + if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; #endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY ASSERT(Check()); free_pages_ -= n; @@ -1642,20 +1656,13 @@ Span* TCMalloc_PageHeap::AllocLarge(Length n) { if (best != NULL) { Carve(best, n, from_released); - if (best->decommitted) { - TCMalloc_SystemCommit(reinterpret_cast<void*>(best->start << kPageShift), static_cast<size_t>(n << kPageShift)); - best->decommitted = false; -#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - pages_committed_since_last_scavenge_ += n; -#endif - } #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - else { - // The newly allocated memory is from a span that's in the normal span list (already committed). Update the - // free committed pages count. - ASSERT(free_committed_pages_ >= n); - free_committed_pages_ -= n; - } + // The newly allocated memory is from a span that's in the normal span list (already committed). Update the + // free committed pages count. + ASSERT(free_committed_pages_ >= n); + free_committed_pages_ -= n; + if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; #endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY ASSERT(Check()); free_pages_ -= n; @@ -1681,29 +1688,34 @@ Span* TCMalloc_PageHeap::Split(Span* span, Length n) { return leftover; } -static ALWAYS_INLINE void propagateDecommittedState(Span* destination, Span* source) -{ - destination->decommitted = source->decommitted; -} - inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) { ASSERT(n > 0); DLL_Remove(span); span->free = 0; Event(span, 'A', n); + if (released) { + // If the span chosen to carve from is decommited, commit the entire span at once to avoid committing spans 1 page at a time. + ASSERT(span->decommitted); + TCMalloc_SystemCommit(reinterpret_cast<void*>(span->start << kPageShift), static_cast<size_t>(span->length << kPageShift)); + span->decommitted = false; +#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY + free_committed_pages_ += span->length; +#endif + } + const int extra = static_cast<int>(span->length - n); ASSERT(extra >= 0); if (extra > 0) { Span* leftover = NewSpan(span->start + n, extra); leftover->free = 1; - propagateDecommittedState(leftover, span); + leftover->decommitted = false; Event(leftover, 'S', extra); RecordSpan(leftover); // Place leftover span on appropriate free list SpanList* listpair = (static_cast<size_t>(extra) < kMaxPages) ? &free_[extra] : &large_; - Span* dst = released ? &listpair->returned : &listpair->normal; + Span* dst = &listpair->normal; DLL_Prepend(dst, leftover); span->length = n; @@ -1798,6 +1810,8 @@ inline void TCMalloc_PageHeap::Delete(Span* span) { // If the merged span is decommitted, that means we decommitted any neighboring spans that were // committed. Update the free committed pages count. free_committed_pages_ -= neighboringCommittedSpansLength; + if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; } else { // If the merged span remains committed, add the deleted span's size to the free committed pages count. free_committed_pages_ += n; @@ -1962,10 +1976,6 @@ bool TCMalloc_PageHeap::GrowHeap(Length n) { } ask = actual_size >> kPageShift; -#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - pages_committed_since_last_scavenge_ += ask; -#endif - uint64_t old_system_bytes = system_bytes_; system_bytes_ += (ask << kPageShift); const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; @@ -2328,7 +2338,7 @@ static TCMalloc_Central_FreeListPadded central_cache[kNumClasses]; // Page-level allocator static SpinLock pageheap_lock = SPINLOCK_INITIALIZER; -static void* pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(void*) - 1) / sizeof(void*)]; +static AllocAlignmentInteger pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(AllocAlignmentInteger) - 1) / sizeof(AllocAlignmentInteger)]; static bool phinited = false; // Avoid extra level of indirection by making "pageheap" be just an alias @@ -2363,15 +2373,15 @@ void TCMalloc_PageHeap::scavengerThread() #endif while (1) { - if (!shouldContinueScavenging()) { + if (!shouldScavenge()) { pthread_mutex_lock(&m_scavengeMutex); m_scavengeThreadActive = false; - // Block until there are enough freed pages to release back to the system. + // Block until there are enough free committed pages to release back to the system. pthread_cond_wait(&m_scavengeCondition, &m_scavengeMutex); m_scavengeThreadActive = true; pthread_mutex_unlock(&m_scavengeMutex); } - sleep(kScavengeTimerDelayInSeconds); + sleep(kScavengeDelayInSeconds); { SpinLockHolder h(&pageheap_lock); pageheap->scavenge(); @@ -2388,7 +2398,7 @@ void TCMalloc_PageHeap::periodicScavenge() pageheap->scavenge(); } - if (!shouldContinueScavenging()) { + if (!shouldScavenge()) { m_scavengingScheduled = false; dispatch_suspend(m_scavengeTimer); } @@ -3933,6 +3943,8 @@ static inline void* cpp_alloc(size_t size, bool nothrow) { } } +#if ENABLE(GLOBAL_FASTMALLOC_NEW) + void* operator new(size_t size) { void* p = cpp_alloc(size, false); // We keep this next instruction out of cpp_alloc for a reason: when @@ -3987,6 +3999,8 @@ void operator delete[](void* p, const std::nothrow_t&) __THROW { do_free(p); } +#endif + extern "C" void* memalign(size_t align, size_t size) __THROW { void* result = do_memalign(align, size); MallocHook::InvokeNewHook(result, size); @@ -4102,7 +4116,62 @@ void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; #endif -#if defined(WTF_CHANGES) && OS(DARWIN) +#ifdef WTF_CHANGES +void releaseFastMallocFreeMemory() +{ + // Flush free pages in the current thread cache back to the page heap. + // Low watermark mechanism in Scavenge() prevents full return on the first pass. + // The second pass flushes everything. + if (TCMalloc_ThreadCache* threadCache = TCMalloc_ThreadCache::GetCacheIfPresent()) { + threadCache->Scavenge(); + threadCache->Scavenge(); + } + + SpinLockHolder h(&pageheap_lock); + pageheap->ReleaseFreePages(); +} + +FastMallocStatistics fastMallocStatistics() +{ + FastMallocStatistics statistics; + + SpinLockHolder lockHolder(&pageheap_lock); + statistics.reservedVMBytes = static_cast<size_t>(pageheap->SystemBytes()); + statistics.committedVMBytes = statistics.reservedVMBytes - pageheap->ReturnedBytes(); + + statistics.freeListBytes = 0; + for (unsigned cl = 0; cl < kNumClasses; ++cl) { + const int length = central_cache[cl].length(); + const int tc_length = central_cache[cl].tc_length(); + + statistics.freeListBytes += ByteSizeForClass(cl) * (length + tc_length); + } + for (TCMalloc_ThreadCache* threadCache = thread_heaps; threadCache ; threadCache = threadCache->next_) + statistics.freeListBytes += threadCache->Size(); + + return statistics; +} + +size_t fastMallocSize(const void* ptr) +{ + const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; + Span* span = pageheap->GetDescriptorEnsureSafe(p); + + if (!span || span->free) + return 0; + + for (void* free = span->objects; free != NULL; free = *((void**) free)) { + if (ptr == free) + return 0; + } + + if (size_t cl = span->sizeclass) + return ByteSizeForClass(cl); + + return span->length << kPageShift; +} + +#if OS(DARWIN) class FreeObjectFinder { const RemoteMemoryReader& m_reader; @@ -4388,6 +4457,9 @@ malloc_introspection_t jscore_fastmalloc_introspection = { &FastMallocZone::enum #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !OS(IPHONE_OS) , 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher. #endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) && !OS(IPHONE_OS) + , 0, 0, 0, 0 // These members will not be used unless the zone advertises itself as version seven or higher. +#endif }; } @@ -4419,44 +4491,9 @@ void FastMallocZone::init() static FastMallocZone zone(pageheap, &thread_heaps, static_cast<TCMalloc_Central_FreeListPadded*>(central_cache), &span_allocator, &threadheap_allocator); } -#endif - -#if WTF_CHANGES -void releaseFastMallocFreeMemory() -{ - // Flush free pages in the current thread cache back to the page heap. - // Low watermark mechanism in Scavenge() prevents full return on the first pass. - // The second pass flushes everything. - if (TCMalloc_ThreadCache* threadCache = TCMalloc_ThreadCache::GetCacheIfPresent()) { - threadCache->Scavenge(); - threadCache->Scavenge(); - } - - SpinLockHolder h(&pageheap_lock); - pageheap->ReleaseFreePages(); -} - -FastMallocStatistics fastMallocStatistics() -{ - FastMallocStatistics statistics; - { - SpinLockHolder lockHolder(&pageheap_lock); - statistics.heapSize = static_cast<size_t>(pageheap->SystemBytes()); - statistics.freeSizeInHeap = static_cast<size_t>(pageheap->FreeBytes()); - statistics.returnedSize = pageheap->ReturnedBytes(); - statistics.freeSizeInCaches = 0; - for (TCMalloc_ThreadCache* threadCache = thread_heaps; threadCache ; threadCache = threadCache->next_) - statistics.freeSizeInCaches += threadCache->Size(); - } - for (unsigned cl = 0; cl < kNumClasses; ++cl) { - const int length = central_cache[cl].length(); - const int tc_length = central_cache[cl].tc_length(); - statistics.freeSizeInCaches += ByteSizeForClass(cl) * (length + tc_length); - } - return statistics; -} +#endif // OS(DARWIN) } // namespace WTF -#endif +#endif // WTF_CHANGES #endif // FORCE_SYSTEM_MALLOC diff --git a/JavaScriptCore/wtf/FastMalloc.h b/JavaScriptCore/wtf/FastMalloc.h index 74d4307..1ccd6a6 100644 --- a/JavaScriptCore/wtf/FastMalloc.h +++ b/JavaScriptCore/wtf/FastMalloc.h @@ -34,6 +34,7 @@ namespace WTF { void* fastCalloc(size_t numElements, size_t elementSize); void* fastRealloc(void*, size_t); char* fastStrDup(const char*); + size_t fastMallocSize(const void*); struct TryMallocReturnValue { TryMallocReturnValue(void* data) @@ -82,10 +83,9 @@ namespace WTF { void releaseFastMallocFreeMemory(); struct FastMallocStatistics { - size_t heapSize; - size_t freeSizeInHeap; - size_t freeSizeInCaches; - size_t returnedSize; + size_t reservedVMBytes; + size_t committedVMBytes; + size_t freeListBytes; }; FastMallocStatistics fastMallocStatistics(); @@ -180,16 +180,17 @@ namespace WTF { } // namespace WTF -using WTF::fastMalloc; -using WTF::fastZeroedMalloc; using WTF::fastCalloc; +using WTF::fastFree; +using WTF::fastMalloc; +using WTF::fastMallocSize; using WTF::fastRealloc; -using WTF::tryFastMalloc; -using WTF::tryFastZeroedMalloc; +using WTF::fastStrDup; +using WTF::fastZeroedMalloc; using WTF::tryFastCalloc; +using WTF::tryFastMalloc; using WTF::tryFastRealloc; -using WTF::fastFree; -using WTF::fastStrDup; +using WTF::tryFastZeroedMalloc; #ifndef NDEBUG using WTF::fastMallocForbid; @@ -215,8 +216,7 @@ using WTF::fastMallocAllow; // debug-only code to make sure we don't use the system malloc via the default operator // new by accident. -// We musn't customize the global operator new and delete for the Qt port. -#if !PLATFORM(QT) +#if ENABLE(GLOBAL_FASTMALLOC_NEW) #if COMPILER(MSVC) #pragma warning(push) diff --git a/JavaScriptCore/wtf/HashCountedSet.h b/JavaScriptCore/wtf/HashCountedSet.h index 165eb41..4ed75c5 100644 --- a/JavaScriptCore/wtf/HashCountedSet.h +++ b/JavaScriptCore/wtf/HashCountedSet.h @@ -43,7 +43,7 @@ namespace WTF { int capacity() const; bool isEmpty() const; - // iterators iterate over pairs of values and counts + // Iterators iterate over pairs of values and counts. iterator begin(); iterator end(); const_iterator begin() const; @@ -54,21 +54,21 @@ namespace WTF { bool contains(const ValueType&) const; unsigned count(const ValueType&) const; - // increases the count if an equal value is already present - // the return value is a pair of an interator to the new value's location, - // and a bool that is true if an new entry was added + // Increases the count if an equal value is already present + // the return value is a pair of an interator to the new value's + // location, and a bool that is true if an new entry was added. std::pair<iterator, bool> add(const ValueType&); - // reduces the count of the value, and removes it if count - // goes down to zero - void remove(const ValueType&); - void remove(iterator); + // Reduces the count of the value, and removes it if count + // goes down to zero, returns true if the value is removed. + bool remove(const ValueType&); + bool remove(iterator); - // removes the value, regardless of its count + // Removes the value, regardless of its count. void removeAll(iterator); void removeAll(const ValueType&); - // clears the whole set + // Clears the whole set. void clear(); private: @@ -150,24 +150,27 @@ namespace WTF { } template<typename Value, typename HashFunctions, typename Traits> - inline void HashCountedSet<Value, HashFunctions, Traits>::remove(const ValueType& value) + inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(const ValueType& value) { - remove(find(value)); + return remove(find(value)); } template<typename Value, typename HashFunctions, typename Traits> - inline void HashCountedSet<Value, HashFunctions, Traits>::remove(iterator it) + inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(iterator it) { if (it == end()) - return; + return false; unsigned oldVal = it->second; - ASSERT(oldVal != 0); + ASSERT(oldVal); unsigned newVal = oldVal - 1; - if (newVal == 0) - m_impl.remove(it); - else + if (newVal) { it->second = newVal; + return false; + } + + m_impl.remove(it); + return true; } template<typename Value, typename HashFunctions, typename Traits> diff --git a/JavaScriptCore/wtf/HashMap.h b/JavaScriptCore/wtf/HashMap.h index d63a8d4..09094d1 100644 --- a/JavaScriptCore/wtf/HashMap.h +++ b/JavaScriptCore/wtf/HashMap.h @@ -133,9 +133,10 @@ namespace WTF { static unsigned hash(const T& key) { return Translator::hash(key); } static bool equal(const KeyType& a, const T& b) { return Translator::equal(a, b); } - static void translate(ValueType& location, const T& key, const MappedType&, unsigned hashCode) + static void translate(ValueType& location, const T& key, const MappedType& mapped, unsigned hashCode) { Translator::translate(location.first, key, hashCode); + location.second = mapped; } }; diff --git a/JavaScriptCore/wtf/MD5.cpp b/JavaScriptCore/wtf/MD5.cpp new file mode 100644 index 0000000..cd1837a --- /dev/null +++ b/JavaScriptCore/wtf/MD5.cpp @@ -0,0 +1,304 @@ +// The original file was copied from sqlite, and was in the public domain. +// Modifications Copyright 2006 Google Inc. All Rights Reserved +/* + * Copyright (C) 2010 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. + */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, construct an + * MD5 instance, call addBytes as needed on buffers full of bytes, + * and then call checksum, which will fill a supplied 16-byte array + * with the digest. + */ + +#include "config.h" +#include "MD5.h" + +#include "Assertions.h" +#ifndef NDEBUG +#include "StringExtras.h" +#include "text/CString.h" +#endif + +namespace WTF { + +#ifdef NDEBUG +static inline void testMD5() { } +#else +// MD5 test case. +static bool isTestMD5Done; + +static void expectMD5(CString input, CString expected) +{ + MD5 md5; + md5.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length()); + Vector<uint8_t, 16> digest = md5.checksum(); + char* buf = 0; + CString actual = CString::newUninitialized(32, buf); + for (size_t i = 0; i < 16; i++) { + snprintf(buf, 3, "%02x", digest.at(i)); + buf += 2; + } + ASSERT_WITH_MESSAGE(actual == expected, "input:%s[%d] actual:%s expected:%s", input.data(), input.length(), actual.data(), expected.data()); +} + +static void testMD5() +{ + if (isTestMD5Done) + return; + isTestMD5Done = true; + + // MD5 Test suite from http://www.ietf.org/rfc/rfc1321.txt + expectMD5("", "d41d8cd98f00b204e9800998ecf8427e"); + expectMD5("a", "0cc175b9c0f1b6a831c399e269772661"); + expectMD5("abc", "900150983cd24fb0d6963f7d28e17f72"); + expectMD5("message digest", "f96b697d7cb7938d525a2f31aaf161d0"); + expectMD5("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); + expectMD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"); + expectMD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); +} +#endif + +// Note: this code is harmless on little-endian machines. + +static void reverseBytes(uint8_t* buf, unsigned longs) +{ + ASSERT(longs > 0); + do { + uint32_t t = static_cast<uint32_t>(buf[3] << 8 | buf[2]) << 16 | buf[1] << 8 | buf[0]; + ASSERT_WITH_MESSAGE(!(reinterpret_cast<uintptr_t>(buf) % sizeof(t)), "alignment error of buf"); + *reinterpret_cast<uint32_t *>(buf) = t; + buf += 4; + } while (--longs); +} + +// The four core functions. +// F1 is originally defined as (x & y | ~x & z), but optimized somewhat: 4 bit ops -> 3 bit ops. +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +static void MD5Transform(uint32_t buf[4], const uint32_t in[16]) +{ + uint32_t a = buf[0]; + uint32_t b = buf[1]; + uint32_t c = buf[2]; + uint32_t d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +MD5::MD5() +{ + testMD5(); + m_buf[0] = 0x67452301; + m_buf[1] = 0xefcdab89; + m_buf[2] = 0x98badcfe; + m_buf[3] = 0x10325476; + m_bits[0] = 0; + m_bits[1] = 0; + memset(m_in, 0, sizeof(m_in)); + ASSERT_WITH_MESSAGE(!(reinterpret_cast<uintptr_t>(m_in) % sizeof(uint32_t)), "alignment error of m_in"); +} + +void MD5::addBytes(const uint8_t* input, size_t length) +{ + const uint8_t* buf = input; + + // Update bitcount + uint32_t t = m_bits[0]; + m_bits[0] = t + (length << 3); + if (m_bits[0] < t) + m_bits[1]++; // Carry from low to high + m_bits[1] += length >> 29; + + t = (t >> 3) & 0x3f; // Bytes already in shsInfo->data + + // Handle any leading odd-sized chunks + + if (t) { + uint8_t* p = m_in + t; + + t = 64 - t; + if (length < t) { + memcpy(p, buf, length); + return; + } + memcpy(p, buf, t); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned. + buf += t; + length -= t; + } + + // Process data in 64-byte chunks + + while (length >= 64) { + memcpy(m_in, buf, 64); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned. + buf += 64; + length -= 64; + } + + // Handle any remaining bytes of data. + memcpy(m_in, buf, length); +} + +Vector<uint8_t, 16> MD5::checksum() +{ + // Compute number of bytes mod 64 + unsigned count = (m_bits[0] >> 3) & 0x3F; + + // Set the first char of padding to 0x80. This is safe since there is + // always at least one byte free + uint8_t* p = m_in + count; + *p++ = 0x80; + + // Bytes of padding needed to make 64 bytes + count = 64 - 1 - count; + + // Pad out to 56 mod 64 + if (count < 8) { + // Two lots of padding: Pad the first block to 64 bytes + memset(p, 0, count); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t *>(m_in)); // m_in is 4-byte aligned. + + // Now fill the next block with 56 bytes + memset(m_in, 0, 56); + } else { + // Pad block to 56 bytes + memset(p, 0, count - 8); + } + reverseBytes(m_in, 14); + + // Append length in bits and transform + // m_in is 4-byte aligned. + (reinterpret_cast<uint32_t*>(m_in))[14] = m_bits[0]; + (reinterpret_cast<uint32_t*>(m_in))[15] = m_bits[1]; + + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); + reverseBytes(reinterpret_cast<uint8_t*>(m_buf), 4); + Vector<uint8_t, 16> digest; + digest.append(reinterpret_cast<uint8_t*>(m_buf), 16); + + // In case it's sensitive + memset(m_buf, 0, sizeof(m_buf)); + memset(m_bits, 0, sizeof(m_bits)); + memset(m_in, 0, sizeof(m_in)); + return digest; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/MD5.h b/JavaScriptCore/wtf/MD5.h new file mode 100644 index 0000000..8ebfc45 --- /dev/null +++ b/JavaScriptCore/wtf/MD5.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 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 WTF_MD5_h +#define WTF_MD5_h + +#include <wtf/Vector.h> + +namespace WTF { + +class MD5 { +public: + MD5(); + + void addBytes(const Vector<uint8_t>& input) + { + addBytes(input.data(), input.size()); + } + void addBytes(const uint8_t* input, size_t length); + + // checksum has a side effect of resetting the state of the object. + Vector<uint8_t, 16> checksum(); + +private: + uint32_t m_buf[4]; + uint32_t m_bits[2]; + uint8_t m_in[64]; +}; + +} // namespace WTF + +using WTF::MD5; + +#endif // WTF_MD5_h diff --git a/JavaScriptCore/wtf/MainThread.cpp b/JavaScriptCore/wtf/MainThread.cpp index 40a4ae5..a041bb2 100644 --- a/JavaScriptCore/wtf/MainThread.cpp +++ b/JavaScriptCore/wtf/MainThread.cpp @@ -29,11 +29,15 @@ #include "config.h" #include "MainThread.h" -#include "StdLibExtras.h" #include "CurrentTime.h" #include "Deque.h" +#include "StdLibExtras.h" #include "Threading.h" +#if PLATFORM(CHROMIUM) +#error Chromium uses a different main thread implementation +#endif + namespace WTF { struct FunctionWithContext { @@ -52,8 +56,11 @@ struct FunctionWithContext { typedef Deque<FunctionWithContext> FunctionQueue; static bool callbacksPaused; // This global variable is only accessed from main thread. +#if !PLATFORM(MAC) && !PLATFORM(QT) +static ThreadIdentifier mainThreadIdentifier; +#endif -Mutex& mainThreadFunctionQueueMutex() +static Mutex& mainThreadFunctionQueueMutex() { DEFINE_STATIC_LOCAL(Mutex, staticMutex, ()); return staticMutex; @@ -65,12 +72,51 @@ static FunctionQueue& functionQueue() return staticFunctionQueue; } + +#if !PLATFORM(MAC) + void initializeMainThread() { + static bool initializedMainThread; + if (initializedMainThread) + return; + initializedMainThread = true; + +#if !PLATFORM(QT) + mainThreadIdentifier = currentThread(); +#endif + + mainThreadFunctionQueueMutex(); + initializeMainThreadPlatform(); +} + +#else + +static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT; + +static void initializeMainThreadOnce() +{ mainThreadFunctionQueueMutex(); initializeMainThreadPlatform(); } +void initializeMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce); +} + +static void initializeMainThreadToProcessMainThreadOnce() +{ + mainThreadFunctionQueueMutex(); + initializeMainThreadToProcessMainThreadPlatform(); +} + +void initializeMainThreadToProcessMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce); +} +#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; @@ -152,4 +198,11 @@ void setMainThreadCallbacksPaused(bool paused) scheduleDispatchFunctionsOnMainThread(); } +#if !PLATFORM(MAC) && !PLATFORM(QT) +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} +#endif + } // namespace WTF diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h index 8c0275b..d037d0b 100644 --- a/JavaScriptCore/wtf/MainThread.h +++ b/JavaScriptCore/wtf/MainThread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -30,32 +30,40 @@ #ifndef MainThread_h #define MainThread_h -namespace WTF { +#include <stdint.h> -class Mutex; +namespace WTF { +typedef uint32_t ThreadIdentifier; typedef void MainThreadFunction(void*); -void callOnMainThread(MainThreadFunction*, void* context); +// Must be called from the main thread. +void initializeMainThread(); -// Blocks the thread until the call finishes on the main thread. Misusing this can easily cause deadlocks. +void callOnMainThread(MainThreadFunction*, void* context); void callOnMainThreadAndWait(MainThreadFunction*, void* context); - void setMainThreadCallbacksPaused(bool paused); -// Must be called from the main thread (Darwin is an exception to this rule). -void initializeMainThread(); +bool isMainThread(); -// These functions are internal to the callOnMainThread implementation. +// NOTE: these functions are internal to the callOnMainThread implementation. void initializeMainThreadPlatform(); void scheduleDispatchFunctionsOnMainThread(); -Mutex& mainThreadFunctionQueueMutex(); void dispatchFunctionsFromMainThread(); +#if PLATFORM(MAC) +// This version of initializeMainThread sets up the main thread as corresponding +// to the process's main thread, and not necessarily the thread that calls this +// function. It should only be used as a legacy aid for Mac WebKit. +void initializeMainThreadToProcessMainThread(); +void initializeMainThreadToProcessMainThreadPlatform(); +#endif + } // namespace WTF using WTF::callOnMainThread; using WTF::callOnMainThreadAndWait; using WTF::setMainThreadCallbacksPaused; +using WTF::isMainThread; #endif // MainThread_h diff --git a/JavaScriptCore/wtf/MathExtras.h b/JavaScriptCore/wtf/MathExtras.h index 8e93ee8..1f77b61 100644 --- a/JavaScriptCore/wtf/MathExtras.h +++ b/JavaScriptCore/wtf/MathExtras.h @@ -122,6 +122,10 @@ inline double trunc(double num) { return num > 0 ? floor(num) : ceil(num); } #endif #if COMPILER(MSVC) +// The 64bit version of abs() is already defined in stdlib.h which comes with VC10 +#if COMPILER(MSVC9_OR_LOWER) +inline long long abs(long long num) { return _abs64(num); } +#endif inline bool isinf(double num) { return !_finite(num) && !_isnan(num); } inline bool isnan(double num) { return !!_isnan(num); } @@ -186,9 +190,7 @@ inline float deg2turn(float d) { return d / 360.0f; } inline float rad2grad(float r) { return r * 200.0f / piFloat; } inline float grad2rad(float g) { return g * piFloat / 200.0f; } -// ANDROID -// TODO: Upstream to webkit.org -#if !COMPILER(MSVC) && !COMPILER(RVCT) && !COMPILER(WINSCW) +#if !COMPILER(MSVC) && !COMPILER(WINSCW) && !(COMPILER(RVCT) && OS(SYMBIAN)) using std::isfinite; using std::isinf; using std::isnan; diff --git a/JavaScriptCore/wtf/OwnFastMallocPtr.h b/JavaScriptCore/wtf/OwnFastMallocPtr.h index c88235a..8b6cbf4 100644 --- a/JavaScriptCore/wtf/OwnFastMallocPtr.h +++ b/JavaScriptCore/wtf/OwnFastMallocPtr.h @@ -35,7 +35,7 @@ namespace WTF { ~OwnFastMallocPtr() { - fastFree(m_ptr); + fastFree(const_cast<void*>(static_cast<const void*>(const_cast<const T*>(m_ptr)))); } T* get() const { return m_ptr; } diff --git a/JavaScriptCore/wtf/OwnPtr.h b/JavaScriptCore/wtf/OwnPtr.h index b7e62b1..af1684b 100644 --- a/JavaScriptCore/wtf/OwnPtr.h +++ b/JavaScriptCore/wtf/OwnPtr.h @@ -40,7 +40,6 @@ namespace WTF { typedef ValueType* PtrType; explicit OwnPtr(PtrType ptr = 0) : m_ptr(ptr) { } - OwnPtr(std::auto_ptr<ValueType> autoPtr) : m_ptr(autoPtr.release()) { } // See comment in PassOwnPtr.h for why this takes a const reference. template <typename U> OwnPtr(const PassOwnPtr<U>& o); @@ -58,8 +57,6 @@ namespace WTF { // FIXME: This should be renamed to adopt. void set(PtrType ptr) { ASSERT(!ptr || m_ptr != ptr); deleteOwnedPtr(m_ptr); m_ptr = ptr; } - void adopt(std::auto_ptr<ValueType> autoPtr) { ASSERT(!autoPtr.get() || m_ptr != autoPtr.get()); deleteOwnedPtr(m_ptr); m_ptr = autoPtr.release(); } - void clear() { deleteOwnedPtr(m_ptr); m_ptr = 0; } ValueType& operator*() const { ASSERT(m_ptr); return *m_ptr; } diff --git a/JavaScriptCore/wtf/OwnPtrCommon.h b/JavaScriptCore/wtf/OwnPtrCommon.h index 6d91a54..c59fdc5 100644 --- a/JavaScriptCore/wtf/OwnPtrCommon.h +++ b/JavaScriptCore/wtf/OwnPtrCommon.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile, Inc. + * Copyright (C) 2010 Company 100 Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,6 +38,14 @@ typedef struct HPEN__* HPEN; typedef struct HRGN__* HRGN; #endif +#if PLATFORM(BREWMP) +// Forward delcarations at this point avoid the need to include BREW includes +// in WTF headers. +typedef struct _IFileMgr IFileMgr; +typedef struct _IFile IFile; +typedef struct IBitmap IBitmap; +#endif + namespace WTF { template <typename T> inline void deleteOwnedPtr(T* ptr) @@ -56,6 +65,12 @@ namespace WTF { void deleteOwnedPtr(HRGN); #endif +#if PLATFORM(BREWMP) + void deleteOwnedPtr(IFileMgr*); + void deleteOwnedPtr(IFile*); + void deleteOwnedPtr(IBitmap*); +#endif + } // namespace WTF #endif // WTF_OwnPtrCommon_h diff --git a/JavaScriptCore/wtf/PassRefPtr.h b/JavaScriptCore/wtf/PassRefPtr.h index 9c6e44f..d7a9341 100644 --- a/JavaScriptCore/wtf/PassRefPtr.h +++ b/JavaScriptCore/wtf/PassRefPtr.h @@ -33,19 +33,32 @@ namespace WTF { // Remove inline for WINSCW compiler to prevent the compiler agressively resolving // T::ref() and T::deref(), which will fail compiling when PassRefPtr<T> is used as // a class member or function arguments before T is defined. + + // [Qt]r57240 broke Qt build (might be a gcc bug) + // FIXME! See: https://bugs.webkit.org/show_bug.cgi?id=37253 template<typename T> #if !COMPILER(WINSCW) +#if !PLATFORM(QT) + ALWAYS_INLINE +#else inline #endif +#endif void refIfNotNull(T* ptr) { if (UNLIKELY(ptr != 0)) ptr->ref(); } + // [Qt]r57240 broke Qt build (might be a gcc bug) + // FIXME! See: https://bugs.webkit.org/show_bug.cgi?id=37253 template<typename T> #if !COMPILER(WINSCW) - inline +#if !PLATFORM(QT) + ALWAYS_INLINE +#else + inline +#endif #endif void derefIfNotNull(T* ptr) { diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index a6ded58..f667b9a 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -58,11 +58,14 @@ /* ==== COMPILER() - the compiler being used to build the project ==== */ /* COMPILER(MSVC) Microsoft Visual C++ */ -/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/ +/* COMPILER(MSVC7_OR_LOWER) Microsoft Visual C++ 2003 or lower*/ +/* COMPILER(MSVC9_OR_LOWER) Microsoft Visual C++ 2008 or lower*/ #if defined(_MSC_VER) #define WTF_COMPILER_MSVC 1 #if _MSC_VER < 1400 -#define WTF_COMPILER_MSVC7 1 +#define WTF_COMPILER_MSVC7_OR_LOWER 1 +#elif _MSC_VER < 1600 +#define WTF_COMPILER_MSVC9_OR_LOWER 1 #endif #endif @@ -79,13 +82,21 @@ #endif /* COMPILER(MINGW) - MinGW GCC */ -#if defined(MINGW) || defined(__MINGW32__) +/* COMPILER(MINGW64) - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */ +#if defined(__MINGW32__) #define WTF_COMPILER_MINGW 1 -#endif +#include <_mingw.h> /* private MinGW header */ + #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */ + #define WTF_COMPILER_MINGW64 1 + #endif /* __MINGW64_VERSION_MAJOR */ +#endif /* __MINGW32__ */ /* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */ #if defined(__WINSCW__) #define WTF_COMPILER_WINSCW 1 +/* cross-compiling, it is not really windows */ +#undef WIN32 +#undef _WIN32 #endif @@ -102,7 +113,28 @@ /* CPU(IA64) - Itanium / IA-64 */ #if defined(__ia64__) #define WTF_CPU_IA64 1 +/* 32-bit mode on Itanium */ +#if !defined(__LP64__) +#define WTF_CPU_IA64_32 1 +#endif +#endif + +/* CPU(MIPS) - MIPS 32-bit */ +/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now. */ +#if (defined(mips) || defined(__mips__)) \ + && defined(_ABIO32) +#define WTF_CPU_MIPS 1 +#if defined(__MIPSEB__) +#define WTF_CPU_BIG_ENDIAN 1 #endif +#define WTF_MIPS_PIC (defined __PIC__) +#define WTF_MIPS_ARCH __mips +#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v) +#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v) +#define WTF_MIPS_ARCH_REV __mips_isa_rev +#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v) +#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float) +#endif /* MIPS */ /* CPU(PPC) - PowerPC 32-bit */ #if defined(__ppc__) \ @@ -142,7 +174,7 @@ /* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */ #if CPU(SPARC32) || CPU(SPARC64) -#define WTF_CPU_SPARC +#define WTF_CPU_SPARC 1 #endif /* CPU(X86) - i386 / x86 32-bit */ @@ -162,7 +194,9 @@ /* CPU(ARM) - ARM, any version*/ #if defined(arm) \ - || defined(__arm__) + || defined(__arm__) \ + || defined(ARM) \ + || defined(_ARM_) #define WTF_CPU_ARM 1 #if defined(__ARMEB__) @@ -171,6 +205,7 @@ #elif !defined(__ARM_EABI__) \ && !defined(__EABI__) \ && !defined(__VFP_FP__) \ + && !defined(_WIN32_WCE) \ && !defined(ANDROID) #define WTF_CPU_MIDDLE_ENDIAN 1 @@ -371,9 +406,6 @@ /* OS(SYMBIAN) - Symbian */ #if defined (__SYMBIAN32__) -/* we are cross-compiling, it is not really windows */ -#undef WTF_OS_WINDOWS -#undef WTF_PLATFORM_WIN #define WTF_OS_SYMBIAN 1 #endif @@ -537,6 +569,9 @@ #if PLATFORM(QT) #define WTF_USE_QT4_UNICODE 1 +#if !defined(ENABLE_WIDGETS_10_SUPPORT) +#define ENABLE_WIDGETS_10_SUPPORT 1 +#endif #elif OS(WINCE) #define WTF_USE_WINCE_UNICODE 1 #elif PLATFORM(GTK) @@ -552,8 +587,8 @@ #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && CPU(X86_64) #define WTF_USE_PLUGIN_HOST_PROCESS 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 1 +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 1 #endif #if !defined(ENABLE_DASHBOARD_SUPPORT) #define ENABLE_DASHBOARD_SUPPORT 1 @@ -562,10 +597,15 @@ #define HAVE_RUNLOOP_TIMER 1 #endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */ +#if PLATFORM(MAC) +#define WTF_USE_CARBON_SECURE_INPUT_MODE 1 +#endif + #if PLATFORM(CHROMIUM) && OS(DARWIN) #define WTF_PLATFORM_CF 1 #define WTF_USE_PTHREADS 1 #define HAVE_PTHREAD_RWLOCK 1 +#define WTF_USE_CARBON_SECURE_INPUT_MODE 1 #endif #if PLATFORM(QT) && OS(DARWIN) @@ -579,7 +619,7 @@ #define ENABLE_GEOLOCATION 1 #define ENABLE_ICONDATABASE 0 #define ENABLE_INSPECTOR 0 -#define ENABLE_MAC_JAVA_BRIDGE 0 +#define ENABLE_JAVA_BRIDGE 0 #define ENABLE_NETSCAPE_PLUGIN_API 0 #define ENABLE_ORIENTATION_EVENTS 1 #define ENABLE_REPAINT_THROTTLING 1 @@ -593,7 +633,7 @@ #define WTF_USE_PTHREADS 1 #define WTF_PLATFORM_SKIA 1 #define USE_SYSTEM_MALLOC 1 -#define ENABLE_MAC_JAVA_BRIDGE 1 +#define ENABLE_JAVA_BRIDGE 1 #define LOG_DISABLED 1 /* Prevents Webkit from drawing the caret in textfields and textareas This prevents unnecessary invals. */ @@ -608,8 +648,14 @@ #if PLATFORM(WX) #define ENABLE_ASSEMBLER 1 +#define ENABLE_GLOBAL_FASTMALLOC_NEW 0 #if OS(DARWIN) #define WTF_PLATFORM_CF 1 +#ifndef BUILDING_ON_TIGER +#define WTF_USE_CORE_TEXT 1 +#else +#define WTF_USE_ATSUI 1 +#endif #endif #endif @@ -743,6 +789,11 @@ /* ENABLE macro defaults */ +#if PLATFORM(QT) +// We musn't customize the global operator new and delete for the Qt port. +#define ENABLE_GLOBAL_FASTMALLOC_NEW 0 +#endif + /* fastMalloc match validation allows for runtime verification that new is matched by delete, fastMalloc is matched by fastFree, etc. */ #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION) @@ -777,12 +828,16 @@ #define ENABLE_DASHBOARD_SUPPORT 0 #endif +#if !defined(ENABLE_WIDGETS_10_SUPPORT) +#define ENABLE_WIDGETS_10_SUPPORT 0 +#endif + #if !defined(ENABLE_INSPECTOR) #define ENABLE_INSPECTOR 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 0 +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 0 #endif #if !defined(ENABLE_NETSCAPE_PLUGIN_API) @@ -801,6 +856,11 @@ #define ENABLE_OPCODE_STATS 0 #endif +#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW) +#define ENABLE_GLOBAL_FASTMALLOC_NEW 1 +#endif + +#define ENABLE_DEBUG_WITH_BREAKPOINT 0 #define ENABLE_SAMPLING_COUNTERS 0 #define ENABLE_SAMPLING_FLAGS 0 #define ENABLE_OPCODE_SAMPLING 0 @@ -820,6 +880,10 @@ #define ENABLE_NOTIFICATIONS 0 #endif +#if PLATFORM(IPHONE) +#define ENABLE_TEXT_CARET 0 +#endif + #if !defined(ENABLE_TEXT_CARET) #define ENABLE_TEXT_CARET 1 #endif @@ -840,9 +904,12 @@ #endif #if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) -#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) || CPU(IA64) || CPU(ALPHA) +#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) \ + || (CPU(IA64) && !CPU(IA64_32)) \ + || CPU(ALPHA) \ + || CPU(SPARC64) #define WTF_USE_JSVALUE64 1 -#elif CPU(ARM) || CPU(PPC64) +#elif CPU(ARM) || CPU(PPC64) || CPU(MIPS) #define WTF_USE_JSVALUE32 1 #elif OS(WINDOWS) && COMPILER(MINGW) /* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg @@ -885,6 +952,8 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #elif CPU(X86) && OS(WINDOWS) && COMPILER(MINGW) && GCC_VERSION >= 40100 #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif CPU(X86_64) && OS(WINDOWS) && COMPILER(MINGW64) && GCC_VERSION >= 40100 + #define ENABLE_JIT 1 #elif CPU(X86) && OS(WINDOWS) && COMPILER(MSVC) #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 @@ -895,6 +964,11 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JIT 1 #elif CPU(ARM_TRADITIONAL) && OS(LINUX) #define ENABLE_JIT 1 +#elif CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT) + #define ENABLE_JIT 1 +#elif CPU(MIPS) && OS(LINUX) + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 0 #endif #endif /* PLATFORM(QT) */ @@ -959,10 +1033,15 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #if PLATFORM(QT) #if (CPU(X86) && OS(WINDOWS) && COMPILER(MINGW) && GCC_VERSION >= 40100) \ + || (CPU(X86_64) && OS(WINDOWS) && COMPILER(MINGW64) && GCC_VERSION >= 40100) \ || (CPU(X86) && OS(WINDOWS) && COMPILER(MSVC)) \ || (CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100) \ || (CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100) \ - || (CPU(ARM_TRADITIONAL) && OS(LINUX)) + || (CPU(ARM_TRADITIONAL) && OS(LINUX)) \ + || (CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT)) \ + || (CPU(MIPS) && OS(LINUX)) \ + || (CPU(X86) && OS(DARWIN)) \ + || (CPU(X86_64) && OS(DARWIN)) #define ENABLE_YARR 1 #define ENABLE_YARR_JIT 1 #endif @@ -1027,6 +1106,10 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #endif #endif +#if (PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IPHONE) +#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1 +#endif + #if COMPILER(GCC) #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result)) #else diff --git a/JavaScriptCore/wtf/PtrAndFlags.h b/JavaScriptCore/wtf/PtrAndFlags.h deleted file mode 100644 index 1e1bee0..0000000 --- a/JavaScriptCore/wtf/PtrAndFlags.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 PtrAndFlags_h -#define PtrAndFlags_h - -#include <wtf/Assertions.h> - -namespace WTF { - template<class T, typename FlagEnum> class PtrAndFlagsBase { - public: - bool isFlagSet(FlagEnum flagNumber) const { ASSERT(flagNumber < 2); return m_ptrAndFlags & (1 << flagNumber); } - void setFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags |= (1 << flagNumber);} - void clearFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags &= ~(1 << flagNumber);} - T* get() const { return reinterpret_cast<T*>(m_ptrAndFlags & ~3); } - void set(T* ptr) - { - ASSERT(!(reinterpret_cast<intptr_t>(ptr) & 3)); - m_ptrAndFlags = reinterpret_cast<intptr_t>(ptr) | (m_ptrAndFlags & 3); -#ifndef NDEBUG - m_leaksPtr = ptr; -#endif - } - - bool operator!() const { return !get(); } - T* operator->() const { return reinterpret_cast<T*>(m_ptrAndFlags & ~3); } - - protected: - intptr_t m_ptrAndFlags; -#ifndef NDEBUG - void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced. -#endif - }; - - template<class T, typename FlagEnum> class PtrAndFlags : public PtrAndFlagsBase<T, FlagEnum> { - public: - PtrAndFlags() - { - PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0; - } - PtrAndFlags(T* ptr) - { - PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0; - PtrAndFlagsBase<T, FlagEnum>::set(ptr); - } - }; -} // namespace WTF - -using WTF::PtrAndFlagsBase; -using WTF::PtrAndFlags; - -#endif // PtrAndFlags_h diff --git a/JavaScriptCore/wtf/RandomNumber.h b/JavaScriptCore/wtf/RandomNumber.h index fe1687c..e54e9ae 100644 --- a/JavaScriptCore/wtf/RandomNumber.h +++ b/JavaScriptCore/wtf/RandomNumber.h @@ -39,4 +39,7 @@ namespace WTF { } +using WTF::randomNumber; +using WTF::weakRandomNumber; + #endif diff --git a/JavaScriptCore/wtf/RefPtr.h b/JavaScriptCore/wtf/RefPtr.h index 84e841c..eed7933 100644 --- a/JavaScriptCore/wtf/RefPtr.h +++ b/JavaScriptCore/wtf/RefPtr.h @@ -18,6 +18,8 @@ * */ +// RefPtr and PassRefPtr are documented at http://webkit.org/coding/RefPtr.html + #ifndef WTF_RefPtr_h #define WTF_RefPtr_h @@ -79,9 +81,9 @@ namespace WTF { void swap(RefPtr&); - private: static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + private: T* m_ptr; }; diff --git a/JavaScriptCore/wtf/StaticConstructors.h b/JavaScriptCore/wtf/StaticConstructors.h new file mode 100644 index 0000000..8b2df9d --- /dev/null +++ b/JavaScriptCore/wtf/StaticConstructors.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * 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 StaticConstructors_h +#define StaticConstructors_h + +// We need to avoid having static constructors. We achieve this +// with two separate methods for GCC and MSVC. Both methods prevent the static +// initializers from being registered and called on program startup. On GCC, we +// declare the global objects with a different type that can be POD default +// initialized by the linker/loader. On MSVC we use a special compiler feature +// to have the CRT ignore our static initializers. The constructors will never +// be called and the objects will be left uninitialized. +// +// With both of these approaches, we must define and explicitly call an init +// routine that uses placement new to create the objects and overwrite the +// uninitialized placeholders. +// +// This is not completely portable, but is what we have for now without +// changing how a lot of code accesses these global objects. + +#ifdef SKIP_STATIC_CONSTRUCTORS_ON_MSVC +// - Assume that all includes of this header want ALL of their static +// initializers ignored. This is currently the case. This means that if +// a .cc includes this header (or it somehow gets included), all static +// initializers after the include will not be executed. +// - We do this with a pragma, so that all of the static initializer pointers +// go into our own section, and the CRT won't call them. Eventually it would +// be nice if the section was discarded, because we don't want the pointers. +// See: http://msdn.microsoft.com/en-us/library/7977wcck(VS.80).aspx +#pragma warning(disable:4075) +#pragma init_seg(".unwantedstaticinits") +#endif + +#ifndef SKIP_STATIC_CONSTRUCTORS_ON_GCC + // Define an global in the normal way. +#if COMPILER(MSVC7_OR_LOWER) +#define DEFINE_GLOBAL(type, name) \ + const type name; +#elif COMPILER(WINSCW) +#define DEFINE_GLOBAL(type, name, arg...) \ + const type name; +#else +#define DEFINE_GLOBAL(type, name, ...) \ + const type name; +#endif + +#else +// Define an correctly-sized array of pointers to avoid static initialization. +// Use an array of pointers instead of an array of char in case there is some alignment issue. +#if COMPILER(MSVC7_OR_LOWER) +#define DEFINE_GLOBAL(type, name) \ + void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; +#elif COMPILER(WINSCW) +#define DEFINE_GLOBAL(type, name, arg...) \ + void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; +#else +#define DEFINE_GLOBAL(type, name, ...) \ + void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; +#endif +#endif + +#endif // StaticConstructors_h diff --git a/JavaScriptCore/wtf/StdLibExtras.h b/JavaScriptCore/wtf/StdLibExtras.h index 9dfb969..96a929c 100644 --- a/JavaScriptCore/wtf/StdLibExtras.h +++ b/JavaScriptCore/wtf/StdLibExtras.h @@ -26,7 +26,6 @@ #ifndef WTF_StdLibExtras_h #define WTF_StdLibExtras_h -#include <wtf/Platform.h> #include <wtf/Assertions.h> // Use these to declare and define a static local variable (static T;) so that diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index b1ec09f..28e80b8 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -46,7 +46,7 @@ inline int snprintf(char* buffer, size_t count, const char* format, ...) return result; } -#if COMPILER(MSVC7) || OS(WINCE) +#if COMPILER(MSVC7_OR_LOWER) || OS(WINCE) inline int vsnprintf(char* buffer, size_t count, const char* format, va_list args) { diff --git a/JavaScriptCore/wtf/TCSystemAlloc.cpp b/JavaScriptCore/wtf/TCSystemAlloc.cpp index 4d02919..c46ff31 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.cpp +++ b/JavaScriptCore/wtf/TCSystemAlloc.cpp @@ -38,6 +38,7 @@ #include "Assertions.h" #include "TCSpinLock.h" #include "UnusedParam.h" +#include "VMTags.h" #if HAVE(STDINT_H) #include <stdint.h> @@ -178,7 +179,7 @@ static void* TryMmap(size_t size, size_t *actual_size, size_t alignment) { void* result = mmap(NULL, size + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - -1, 0); + VM_TAG_FOR_TCMALLOC_MEMORY, 0); if (result == reinterpret_cast<void*>(MAP_FAILED)) { mmap_failure = true; return NULL; diff --git a/JavaScriptCore/wtf/ThreadSafeShared.h b/JavaScriptCore/wtf/ThreadSafeShared.h new file mode 100644 index 0000000..688747e --- /dev/null +++ b/JavaScriptCore/wtf/ThreadSafeShared.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + * + * + * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based + * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license + * is virtually identical to the Apple license above but is included here for completeness. + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef ThreadSafeShared_h +#define ThreadSafeShared_h + +#include "Platform.h" + +#include <wtf/Atomics.h> +#include <wtf/Noncopyable.h> +#include <wtf/ThreadingPrimitives.h> + +namespace WTF { + +class ThreadSafeSharedBase : public Noncopyable { +public: + ThreadSafeSharedBase(int initialRefCount = 1) + : m_refCount(initialRefCount) + { + } + + void ref() + { +#if USE(LOCKFREE_THREADSAFESHARED) + atomicIncrement(&m_refCount); +#else + MutexLocker locker(m_mutex); + ++m_refCount; +#endif + } + + bool hasOneRef() + { + return refCount() == 1; + } + + int refCount() const + { +#if !USE(LOCKFREE_THREADSAFESHARED) + MutexLocker locker(m_mutex); +#endif + 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); + } +}; + +} // namespace WTF + +using WTF::ThreadSafeShared; + +#endif // ThreadSafeShared_h diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h index 1599562..415a8fc 100644 --- a/JavaScriptCore/wtf/Threading.h +++ b/JavaScriptCore/wtf/Threading.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -61,45 +61,14 @@ #include "Platform.h" -#if OS(WINCE) -#include <windows.h> -#endif - +#include <stdint.h> #include <wtf/Assertions.h> +#include <wtf/Atomics.h> #include <wtf/Locker.h> +#include <wtf/MainThread.h> #include <wtf/Noncopyable.h> - -#if OS(WINDOWS) && !OS(WINCE) -#include <windows.h> -#elif OS(DARWIN) -#include <libkern/OSAtomic.h> -#elif OS(ANDROID) -#include <cutils/atomic.h> -#elif COMPILER(GCC) -#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) -#include <ext/atomicity.h> -#else -#include <bits/atomicity.h> -#endif -#endif - -#if USE(PTHREADS) -#include <pthread.h> -#elif PLATFORM(GTK) -#include <wtf/gtk/GOwnPtr.h> -typedef struct _GMutex GMutex; -typedef struct _GCond GCond; -#endif - -#if PLATFORM(QT) -#include <qglobal.h> -QT_BEGIN_NAMESPACE -class QMutex; -class QWaitCondition; -QT_END_NAMESPACE -#endif - -#include <stdint.h> +#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadingPrimitives.h> // For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc). #define AtomicallyInitializedStatic(T, name) \ @@ -112,6 +81,11 @@ namespace WTF { typedef uint32_t ThreadIdentifier; typedef void* (*ThreadFunction)(void* argument); +// 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(); + // 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); @@ -124,226 +98,18 @@ ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadN void initializeCurrentThreadInternal(const char* threadName); ThreadIdentifier currentThread(); -bool isMainThread(); int waitForThreadCompletion(ThreadIdentifier, void**); void detachThread(ThreadIdentifier); -#if USE(PTHREADS) -typedef pthread_mutex_t PlatformMutex; -#if HAVE(PTHREAD_RWLOCK) -typedef pthread_rwlock_t PlatformReadWriteLock; -#else -typedef void* PlatformReadWriteLock; -#endif -typedef pthread_cond_t PlatformCondition; -#elif PLATFORM(GTK) -typedef GOwnPtr<GMutex> PlatformMutex; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -typedef GOwnPtr<GCond> PlatformCondition; -#elif PLATFORM(QT) -typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; -#elif OS(WINDOWS) -struct PlatformMutex { - CRITICAL_SECTION m_internalMutex; - size_t m_recursionCount; -}; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -struct PlatformCondition { - size_t m_waitersGone; - size_t m_waitersBlocked; - size_t m_waitersToUnblock; - HANDLE m_blockLock; - HANDLE m_blockQueue; - HANDLE m_unblockLock; - - bool timedWait(PlatformMutex&, DWORD durationMilliseconds); - void signal(bool unblockAll); -}; -#else -typedef void* PlatformMutex; -typedef void* PlatformReadWriteLock; -typedef void* PlatformCondition; -#endif - -class Mutex : public Noncopyable { -public: - Mutex(); - ~Mutex(); - - void lock(); - bool tryLock(); - void unlock(); - -public: - PlatformMutex& impl() { return m_mutex; } -private: - PlatformMutex m_mutex; -}; - -typedef Locker<Mutex> MutexLocker; - -class ReadWriteLock : public Noncopyable { -public: - ReadWriteLock(); - ~ReadWriteLock(); - - void readLock(); - bool tryReadLock(); - - void writeLock(); - bool tryWriteLock(); - - void unlock(); - -private: - PlatformReadWriteLock m_readWriteLock; -}; - -class ThreadCondition : public Noncopyable { -public: - ThreadCondition(); - ~ThreadCondition(); - - void wait(Mutex& mutex); - // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. - // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). - bool timedWait(Mutex&, double absoluteTime); - void signal(); - void broadcast(); - -private: - PlatformCondition m_condition; -}; - -#if OS(WINDOWS) -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -#if COMPILER(MINGW) || COMPILER(MSVC7) || OS(WINCE) -inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } -inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } -#else -inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } -inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } -#endif - -#elif OS(DARWIN) -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } -inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } - -#elif OS(ANDROID) - -inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } -inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } - -#elif COMPILER(GCC) && !CPU(SPARC64) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } -inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } - -#endif - -class ThreadSafeSharedBase : public Noncopyable { -public: - ThreadSafeSharedBase(int initialRefCount = 1) - : m_refCount(initialRefCount) - { - } - - void ref() - { -#if USE(LOCKFREE_THREADSAFESHARED) - atomicIncrement(&m_refCount); -#else - MutexLocker locker(m_mutex); - ++m_refCount; -#endif - } - - bool hasOneRef() - { - return refCount() == 1; - } - - int refCount() const - { -#if !USE(LOCKFREE_THREADSAFESHARED) - MutexLocker locker(m_mutex); -#endif - 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(); void lockAtomicallyInitializedStaticMutex(); void unlockAtomicallyInitializedStaticMutex(); } // namespace WTF -using WTF::Mutex; -using WTF::MutexLocker; -using WTF::ThreadCondition; using WTF::ThreadIdentifier; -using WTF::ThreadSafeShared; - -#if USE(LOCKFREE_THREADSAFESHARED) -using WTF::atomicDecrement; -using WTF::atomicIncrement; -#endif - using WTF::createThread; using WTF::currentThread; -using WTF::isMainThread; using WTF::detachThread; using WTF::waitForThreadCompletion; diff --git a/JavaScriptCore/wtf/ThreadingPrimitives.h b/JavaScriptCore/wtf/ThreadingPrimitives.h new file mode 100644 index 0000000..66801c0 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingPrimitives.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ThreadingPrimitives_h +#define ThreadingPrimitives_h + +#include "Platform.h" + +#include <wtf/Assertions.h> +#include <wtf/Locker.h> +#include <wtf/Noncopyable.h> + +#if OS(WINDOWS) +#include <windows.h> +#endif + +#if USE(PTHREADS) +#include <pthread.h> +#elif PLATFORM(GTK) +#include "GOwnPtr.h" +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +#endif + +#if PLATFORM(QT) +#include <qglobal.h> +QT_BEGIN_NAMESPACE +class QMutex; +class QWaitCondition; +QT_END_NAMESPACE +#endif + +namespace WTF { + +#if USE(PTHREADS) +typedef pthread_mutex_t PlatformMutex; +#if HAVE(PTHREAD_RWLOCK) +typedef pthread_rwlock_t PlatformReadWriteLock; +#else +typedef void* PlatformReadWriteLock; +#endif +typedef pthread_cond_t PlatformCondition; +#elif PLATFORM(GTK) +typedef GOwnPtr<GMutex> PlatformMutex; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +typedef GOwnPtr<GCond> PlatformCondition; +#elif PLATFORM(QT) +typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; +#elif OS(WINDOWS) +struct PlatformMutex { + CRITICAL_SECTION m_internalMutex; + size_t m_recursionCount; +}; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +struct PlatformCondition { + size_t m_waitersGone; + size_t m_waitersBlocked; + size_t m_waitersToUnblock; + HANDLE m_blockLock; + HANDLE m_blockQueue; + HANDLE m_unblockLock; + + bool timedWait(PlatformMutex&, DWORD durationMilliseconds); + void signal(bool unblockAll); +}; +#else +typedef void* PlatformMutex; +typedef void* PlatformReadWriteLock; +typedef void* PlatformCondition; +#endif + +class Mutex : public Noncopyable { +public: + Mutex(); + ~Mutex(); + + void lock(); + bool tryLock(); + void unlock(); + +public: + PlatformMutex& impl() { return m_mutex; } +private: + PlatformMutex m_mutex; +}; + +typedef Locker<Mutex> MutexLocker; + +class ReadWriteLock : public Noncopyable { +public: + ReadWriteLock(); + ~ReadWriteLock(); + + void readLock(); + bool tryReadLock(); + + void writeLock(); + bool tryWriteLock(); + + void unlock(); + +private: + PlatformReadWriteLock m_readWriteLock; +}; + +class ThreadCondition : public Noncopyable { +public: + ThreadCondition(); + ~ThreadCondition(); + + void wait(Mutex& mutex); + // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. + // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). + bool timedWait(Mutex&, double absoluteTime); + void signal(); + void broadcast(); + +private: + PlatformCondition m_condition; +}; + +} // namespace WTF + +using WTF::Mutex; +using WTF::MutexLocker; +using WTF::ThreadCondition; + +#endif // ThreadingPrimitives_h diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp index 5a7ff55..7ff9266 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -57,10 +57,6 @@ typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap; static Mutex* atomicallyInitializedStaticMutex; -#if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD) -static pthread_t mainThread; // The thread that was the first to call initializeThreading(), which must be the main thread. -#endif - void clearPthreadHandleForIdentifier(ThreadIdentifier); static Mutex& threadMapMutex() @@ -71,15 +67,12 @@ static Mutex& threadMapMutex() void initializeThreading() { - if (!atomicallyInitializedStaticMutex) { - atomicallyInitializedStaticMutex = new Mutex; - threadMapMutex(); - initializeRandomNumberGenerator(); -#if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD) - mainThread = pthread_self(); -#endif - initializeMainThread(); - } + if (atomicallyInitializedStaticMutex) + return; + + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + initializeRandomNumberGenerator(); } void lockAtomicallyInitializedStaticMutex() @@ -240,15 +233,6 @@ ThreadIdentifier currentThread() return id; } -bool isMainThread() -{ -#if OS(DARWIN) && !PLATFORM(CHROMIUM) && !USE(WEB_THREAD) - return pthread_main_np(); -#else - return pthread_equal(pthread_self(), mainThread); -#endif -} - Mutex::Mutex() { pthread_mutex_init(&m_mutex, NULL); diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp index 73c3f0c..c16be5a 100644 --- a/JavaScriptCore/wtf/ThreadingWin.cpp +++ b/JavaScriptCore/wtf/ThreadingWin.cpp @@ -145,8 +145,6 @@ void unlockAtomicallyInitializedStaticMutex() atomicallyInitializedStaticMutex->unlock(); } -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -155,14 +153,12 @@ static Mutex& threadMapMutex() void initializeThreading() { - if (!atomicallyInitializedStaticMutex) { - atomicallyInitializedStaticMutex = new Mutex; - threadMapMutex(); - initializeRandomNumberGenerator(); - initializeMainThread(); - mainThreadIdentifier = currentThread(); - initializeCurrentThreadInternal("Main Thread"); - } + if (atomicallyInitializedStaticMutex) + return; + + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + initializeRandomNumberGenerator(); } static HashMap<DWORD, HANDLE>& threadMap() @@ -275,11 +271,6 @@ ThreadIdentifier currentThread() return static_cast<ThreadIdentifier>(GetCurrentThreadId()); } -bool isMainThread() -{ - return currentThread() == mainThreadIdentifier; -} - Mutex::Mutex() { m_mutex.m_recursionCount = 0; diff --git a/JavaScriptCore/wtf/VMTags.h b/JavaScriptCore/wtf/VMTags.h index 1ec79d9..6600050 100644 --- a/JavaScriptCore/wtf/VMTags.h +++ b/JavaScriptCore/wtf/VMTags.h @@ -26,30 +26,65 @@ #ifndef VMTags_h #define VMTags_h -#include <wtf/Platform.h> - // On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map // in order to aid tools that inspect system memory use. -#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) +#if OS(DARWIN) #include <mach/vm_statistics.h> -#if defined(VM_MEMORY_JAVASCRIPT_CORE) && defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) && defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) && defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) -#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE) -#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#if !defined(TARGETING_TIGER) + +#if defined(VM_MEMORY_TCMALLOC) +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC) +#else +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53) +#endif // defined(VM_MEMORY_TCMALLOC) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) #define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) #else -#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63) #define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#else #define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65) -#endif // defined(VM_MEMORY_JAVASCRIPT_CORE) && defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) && defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) && defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) + +#else // !defined(TARGETING_TIGER) + +// mmap on Tiger fails with tags that work on Leopard, so fall +// back to Tiger-compatible tags (that also work on Leopard) +// when targeting Tiger. +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 +#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 + +#endif // !defined(TARGETING_TIGER) + +// Tags for vm_map and vm_allocate work on both Tiger and Leopard. + +#if defined(VM_MEMORY_JAVASCRIPT_CORE) +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE) +#else +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63) +#endif // defined(VM_MEMORY_JAVASCRIPT_CORE) + +#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#else +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69) +#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) -#else // OS(DARWIN) && !defined(BUILDING_ON_TIGER) +#else // OS(DARWIN) +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 #define VM_TAG_FOR_COLLECTOR_MEMORY -1 #define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 #define VM_TAG_FOR_REGISTERFILE_MEMORY -1 +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1 -#endif // OS(DARWIN) && !defined(BUILDING_ON_TIGER) +#endif // OS(DARWIN) #endif // VMTags_h diff --git a/JavaScriptCore/wtf/ValueCheck.h b/JavaScriptCore/wtf/ValueCheck.h index cd321b8..2a86eb0 100644 --- a/JavaScriptCore/wtf/ValueCheck.h +++ b/JavaScriptCore/wtf/ValueCheck.h @@ -26,12 +26,7 @@ #ifndef ValueCheck_h #define ValueCheck_h -// For malloc_size and _msize. -#if OS(DARWIN) -#include <malloc/malloc.h> -#elif COMPILER(MSVC) -#include <malloc.h> -#endif +#include <wtf/FastMalloc.h> namespace WTF { @@ -47,13 +42,7 @@ template<typename P> struct ValueCheck<P*> { { if (!p) return; -#if (defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC) || !defined(NDEBUG) -#if OS(DARWIN) - ASSERT(malloc_size(p)); -#elif COMPILER(MSVC) - ASSERT(_msize(const_cast<P*>(p))); -#endif -#endif + ASSERT(fastMallocSize(p)); ValueCheck<P>::checkConsistency(*p); } }; diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 81ea321..e495067 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -286,6 +286,20 @@ namespace WTF { m_buffer = static_cast<T*>(fastMalloc(newCapacity * sizeof(T))); } + bool tryAllocateBuffer(size_t newCapacity) + { + if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T)) + return false; + + T* newBuffer; + if (tryFastMalloc(newCapacity * sizeof(T)).getValue(newBuffer)) { + m_capacity = newCapacity; + m_buffer = newBuffer; + return true; + } + return false; + } + void deallocateBuffer(T* bufferToDeallocate) { if (m_buffer == bufferToDeallocate) { @@ -361,6 +375,7 @@ namespace WTF { void restoreInlineBufferIfNeeded() { } using Base::allocateBuffer; + using Base::tryAllocateBuffer; using Base::deallocateBuffer; using Base::buffer; @@ -405,6 +420,15 @@ namespace WTF { } } + bool tryAllocateBuffer(size_t newCapacity) + { + if (newCapacity > inlineCapacity) + return Base::tryAllocateBuffer(newCapacity); + m_buffer = inlineBuffer(); + m_capacity = inlineCapacity; + return true; + } + void deallocateBuffer(T* bufferToDeallocate) { if (bufferToDeallocate == inlineBuffer()) @@ -538,6 +562,7 @@ namespace WTF { void grow(size_t size); void resize(size_t size); void reserveCapacity(size_t newCapacity); + bool tryReserveCapacity(size_t newCapacity); void reserveInitialCapacity(size_t initialCapacity); void shrinkCapacity(size_t newCapacity); void shrinkToFit() { shrinkCapacity(size()); } @@ -548,6 +573,7 @@ namespace WTF { template<typename U> void append(const U&); template<typename U> void uncheckedAppend(const U& val); template<size_t otherCapacity> void append(const Vector<T, otherCapacity>&); + template<typename U> bool tryAppend(const U*, size_t); template<typename U> void insert(size_t position, const U*, size_t); template<typename U> void insert(size_t position, const U&); @@ -592,6 +618,8 @@ namespace WTF { private: void expandCapacity(size_t newMinCapacity); const T* expandCapacity(size_t newMinCapacity, const T*); + bool tryExpandCapacity(size_t newMinCapacity); + const T* tryExpandCapacity(size_t newMinCapacity, const T*); template<typename U> U* expandCapacity(size_t newMinCapacity, U*); size_t m_size; @@ -742,6 +770,26 @@ namespace WTF { return begin() + index; } + template<typename T, size_t inlineCapacity> + bool Vector<T, inlineCapacity>::tryExpandCapacity(size_t newMinCapacity) + { + return tryReserveCapacity(max(newMinCapacity, max(static_cast<size_t>(16), capacity() + capacity() / 4 + 1))); + } + + template<typename T, size_t inlineCapacity> + const T* Vector<T, inlineCapacity>::tryExpandCapacity(size_t newMinCapacity, const T* ptr) + { + if (ptr < begin() || ptr >= end()) { + if (!tryExpandCapacity(newMinCapacity)) + return 0; + return ptr; + } + size_t index = ptr - begin(); + if (!tryExpandCapacity(newMinCapacity)) + return 0; + return begin() + index; + } + template<typename T, size_t inlineCapacity> template<typename U> inline U* Vector<T, inlineCapacity>::expandCapacity(size_t newMinCapacity, U* ptr) { @@ -797,6 +845,21 @@ namespace WTF { } template<typename T, size_t inlineCapacity> + bool Vector<T, inlineCapacity>::tryReserveCapacity(size_t newCapacity) + { + if (newCapacity <= capacity()) + return true; + T* oldBuffer = begin(); + T* oldEnd = end(); + if (!m_buffer.tryAllocateBuffer(newCapacity)) + return false; + ASSERT(begin()); + TypeOperations::move(oldBuffer, oldEnd, begin()); + m_buffer.deallocateBuffer(oldBuffer); + return true; + } + + template<typename T, size_t inlineCapacity> inline void Vector<T, inlineCapacity>::reserveInitialCapacity(size_t initialCapacity) { ASSERT(!m_size); @@ -848,6 +911,25 @@ namespace WTF { } template<typename T, size_t inlineCapacity> template<typename U> + bool Vector<T, inlineCapacity>::tryAppend(const U* data, size_t dataSize) + { + size_t newSize = m_size + dataSize; + if (newSize > capacity()) { + data = tryExpandCapacity(newSize, data); + if (!data) + return false; + ASSERT(begin()); + } + if (newSize < m_size) + return false; + T* dest = end(); + for (size_t i = 0; i < dataSize; ++i) + new (&dest[i]) T(data[i]); + m_size = newSize; + return true; + } + + template<typename T, size_t inlineCapacity> template<typename U> ALWAYS_INLINE void Vector<T, inlineCapacity>::append(const U& val) { const U* ptr = &val; @@ -857,7 +939,7 @@ namespace WTF { return; } -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) // FIXME: MSVC7 generates compilation errors when trying to assign // a pointer to a Vector of its base class (i.e. can't downcast). So far // I've been unable to determine any logical reason for this, so I can diff --git a/JavaScriptCore/wtf/VectorTraits.h b/JavaScriptCore/wtf/VectorTraits.h index bf77878..3f33b29 100644 --- a/JavaScriptCore/wtf/VectorTraits.h +++ b/JavaScriptCore/wtf/VectorTraits.h @@ -80,9 +80,6 @@ namespace WTF { template<typename P> struct VectorTraits<OwnPtr<P> > : SimpleClassVectorTraits { }; - template<typename P> - struct VectorTraits<std::auto_ptr<P> > : SimpleClassVectorTraits { }; - template<typename First, typename Second> struct VectorTraits<pair<First, Second> > { diff --git a/JavaScriptCore/wtf/WTFThreadData.cpp b/JavaScriptCore/wtf/WTFThreadData.cpp new file mode 100644 index 0000000..0716dc9 --- /dev/null +++ b/JavaScriptCore/wtf/WTFThreadData.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "WTFThreadData.h" + +namespace WTF { + +#if WTFTHREADDATA_MULTITHREADED +ThreadSpecific<WTFThreadData>* WTFThreadData::staticData; +#else +WTFThreadData* WTFThreadData::staticData; +#endif + +WTFThreadData::WTFThreadData() + : m_atomicStringTable(0) + , m_atomicStringTableDestructor(0) +#if USE(JSC) + , m_defaultIdentifierTable(new JSC::IdentifierTable()) + , m_currentIdentifierTable(m_defaultIdentifierTable) +#endif +{ +} + +WTFThreadData::~WTFThreadData() +{ + if (m_atomicStringTableDestructor) + m_atomicStringTableDestructor(m_atomicStringTable); +#if USE(JSC) + delete m_defaultIdentifierTable; +#endif +} + +} // namespace WebCore diff --git a/JavaScriptCore/wtf/WTFThreadData.h b/JavaScriptCore/wtf/WTFThreadData.h new file mode 100644 index 0000000..d2c379b --- /dev/null +++ b/JavaScriptCore/wtf/WTFThreadData.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WTFThreadData_h +#define WTFThreadData_h + +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/text/StringHash.h> + +// This was ENABLE(WORKERS) in WebCore, but this is not defined when compiling JSC. +// However this check was not correct anyway, re this comment: +// // FIXME: Workers are not necessarily the only feature that make per-thread global data necessary. +// // We need to check for e.g. database objects manipulating strings on secondary threads. +// Always enabling this is safe, and should be a better option until we can come up +// with a better define. +#define WTFTHREADDATA_MULTITHREADED 1 + +#if WTFTHREADDATA_MULTITHREADED +#include <wtf/ThreadSpecific.h> +#include <wtf/Threading.h> +#endif + +// FIXME: This is a temporary layering violation while we move more string code to WTF. +namespace WebCore { +class AtomicStringTable; +class StringImpl; +} +using WebCore::StringImpl; + +typedef void (*AtomicStringTableDestructor)(WebCore::AtomicStringTable*); + +#if USE(JSC) +// FIXME: This is a temporary layering violation while we move more string code to WTF. +namespace JSC { + +typedef HashMap<const char*, RefPtr<StringImpl>, PtrHash<const char*> > LiteralIdentifierTable; + +class IdentifierTable : public FastAllocBase { +public: + ~IdentifierTable(); + + std::pair<HashSet<StringImpl*>::iterator, bool> add(StringImpl* value); + template<typename U, typename V> + std::pair<HashSet<StringImpl*>::iterator, bool> add(U value); + + void remove(StringImpl* r) { m_table.remove(r); } + + LiteralIdentifierTable& literalTable() { return m_literalTable; } + +private: + HashSet<StringImpl*> m_table; + LiteralIdentifierTable m_literalTable; +}; + +} +#endif + +namespace WTF { + +class WTFThreadData : public Noncopyable { +public: + WTFThreadData(); + ~WTFThreadData(); + + WebCore::AtomicStringTable* atomicStringTable() + { + return m_atomicStringTable; + } + +#if USE(JSC) + void initializeIdentifierTable(JSC::IdentifierTable* identifierTable) + { + m_defaultIdentifierTable = identifierTable; + m_currentIdentifierTable = identifierTable; + } + + JSC::IdentifierTable* currentIdentifierTable() + { + return m_currentIdentifierTable; + } + + JSC::IdentifierTable* setCurrentIdentifierTable(JSC::IdentifierTable* identifierTable) + { + JSC::IdentifierTable* oldIdentifierTable = m_currentIdentifierTable; + m_currentIdentifierTable = identifierTable; + return oldIdentifierTable; + } + + void resetCurrentIdentifierTable() + { + m_currentIdentifierTable = m_defaultIdentifierTable; + } +#endif + +private: + WebCore::AtomicStringTable* m_atomicStringTable; + AtomicStringTableDestructor m_atomicStringTableDestructor; + +#if USE(JSC) + JSC::IdentifierTable* m_defaultIdentifierTable; + JSC::IdentifierTable* m_currentIdentifierTable; +#endif + +#if WTFTHREADDATA_MULTITHREADED + static JS_EXPORTDATA ThreadSpecific<WTFThreadData>* staticData; +#else + static JS_EXPORTDATA WTFThreadData* staticData; +#endif + friend WTFThreadData& wtfThreadData(); + friend class WebCore::AtomicStringTable; +}; + +inline WTFThreadData& wtfThreadData() +{ +#if WTFTHREADDATA_MULTITHREADED + // WRT WebCore: + // WTFThreadData is used on main thread before it could possibly be used + // on secondary ones, so there is no need for synchronization here. + // WRT JavaScriptCore: + // wtfThreadData() is initially called from initializeThreading(), ensuring + // this is initially called in a pthread_once locked context. + if (!WTFThreadData::staticData) + WTFThreadData::staticData = new ThreadSpecific<WTFThreadData>; + return **WTFThreadData::staticData; +#else + if (!WTFThreadData::staticData) { + WTFThreadData::staticData = static_cast<WTFThreadData*>(fastMalloc(sizeof(WTFThreadData))); + // WTFThreadData constructor indirectly uses staticData, so we need to set up the memory before invoking it. + new (WTFThreadData::staticData) WTFThreadData; + } + return *WTFThreadData::staticData; +#endif +} + +} // namespace WTF + +using WTF::WTFThreadData; +using WTF::wtfThreadData; + +#endif // WTFThreadData_h diff --git a/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp b/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp index dadd82e..c8384e1 100644 --- a/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp +++ b/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp @@ -1,23 +1,30 @@ /* - * Copyright (C) 2010 Company 100, Inc. + * Copyright (C) 2010 Company 100 Inc. All rights reserved. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * This 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "OwnPtrBrew.h" +#include "OwnPtr.h" #include <AEEBitmap.h> #include <AEEFile.h> @@ -25,27 +32,22 @@ namespace WTF { -template <> void freeOwnedPtrBrew<IFileMgr>(IFileMgr* ptr) +void deleteOwnedPtr(IFileMgr* ptr) { if (ptr) IFILEMGR_Release(ptr); } -template <> void freeOwnedPtrBrew<IFile>(IFile* ptr) +void deleteOwnedPtr(IFile* ptr) { if (ptr) IFILE_Release(ptr); } -template <> void freeOwnedPtrBrew<IBitmap>(IBitmap* ptr) +void deleteOwnedPtr(IBitmap* ptr) { if (ptr) IBitmap_Release(ptr); } -template <typename T> void freeOwnedPtrBrew(T* ptr) -{ - FREEIF(ptr); } - -} // namespace WTF diff --git a/JavaScriptCore/wtf/brew/OwnPtrBrew.h b/JavaScriptCore/wtf/brew/OwnPtrBrew.h deleted file mode 100644 index 1bb44fc..0000000 --- a/JavaScriptCore/wtf/brew/OwnPtrBrew.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora Ltd. - * Copyright (C) 2010 Company 100, Inc. - * - * 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 OwnPtrBrew_h -#define OwnPtrBrew_h - -#include <algorithm> -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> - -// Forward delcarations at this point avoid the need to include BREW includes -// in WTF headers. -typedef struct _IFileMgr IFileMgr; -typedef struct _IFile IFile; -typedef struct IBitmap IBitmap; - -namespace WTF { - -template <typename T> void freeOwnedPtrBrew(T* ptr); -template<> void freeOwnedPtrBrew<IFileMgr>(IFileMgr*); -template<> void freeOwnedPtrBrew<IFile>(IFile*); -template<> void freeOwnedPtrBrew<IBitmap>(IBitmap*); - -template <typename T> class OwnPtrBrew : public Noncopyable { -public: - explicit OwnPtrBrew(T* ptr = 0) : m_ptr(ptr) { } - ~OwnPtrBrew() { freeOwnedPtrBrew(m_ptr); } - - T* get() const { return m_ptr; } - T* release() - { - T* ptr = m_ptr; - m_ptr = 0; - return ptr; - } - - T*& outPtr() - { - ASSERT(!m_ptr); - return m_ptr; - } - - void set(T* ptr) - { - ASSERT(!ptr || m_ptr != ptr); - freeOwnedPtrBrew(m_ptr); - m_ptr = ptr; - } - - void clear() - { - freeOwnedPtrBrew(m_ptr); - m_ptr = 0; - } - - T& operator*() const - { - ASSERT(m_ptr); - return *m_ptr; - } - - T* operator->() const - { - ASSERT(m_ptr); - return m_ptr; - } - - bool operator!() const { return !m_ptr; } - - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef T* OwnPtrBrew::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &OwnPtrBrew::m_ptr : 0; } - - void swap(OwnPtrBrew& o) { std::swap(m_ptr, o.m_ptr); } - -private: - T* m_ptr; -}; - -template <typename T> inline void swap(OwnPtrBrew<T>& a, OwnPtrBrew<T>& b) -{ - a.swap(b); -} - -template <typename T, typename U> inline bool operator==(const OwnPtrBrew<T>& a, U* b) -{ - return a.get() == b; -} - -template <typename T, typename U> inline bool operator==(T* a, const OwnPtrBrew<U>& b) -{ - return a == b.get(); -} - -template <typename T, typename U> inline bool operator!=(const OwnPtrBrew<T>& a, U* b) -{ - return a.get() != b; -} - -template <typename T, typename U> inline bool operator!=(T* a, const OwnPtrBrew<U>& b) -{ - return a != b.get(); -} - -template <typename T> inline typename OwnPtrBrew<T>::PtrType getPtr(const OwnPtrBrew<T>& p) -{ - return p.get(); -} - -} // namespace WTF - -using WTF::OwnPtrBrew; - -#endif // OwnPtrBrew_h diff --git a/JavaScriptCore/wtf/brew/ShellBrew.h b/JavaScriptCore/wtf/brew/ShellBrew.h new file mode 100644 index 0000000..7416eca --- /dev/null +++ b/JavaScriptCore/wtf/brew/ShellBrew.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Company 100 Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ShellBrew_h +#define ShellBrew_h + +#include <AEEAppGen.h> +#include <AEEStdLib.h> + +#include <wtf/Assertions.h> +#include <wtf/PassOwnPtr.h> + +namespace WTF { + +template <typename T> +static inline PassOwnPtr<T> createInstance(AEECLSID cls) +{ + T* instance = 0; + + IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell; + ISHELL_CreateInstance(shell, cls, reinterpret_cast<void**>(&instance)); + ASSERT(instance); + + return instance; +} + +} // namespace WTF + +using WTF::createInstance; + +#endif // ShellBrew_h diff --git a/JavaScriptCore/wtf/brew/SystemMallocBrew.h b/JavaScriptCore/wtf/brew/SystemMallocBrew.h new file mode 100644 index 0000000..c973b30 --- /dev/null +++ b/JavaScriptCore/wtf/brew/SystemMallocBrew.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010 Company 100, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 SystemMallocBrew_h +#define SystemMallocBrew_h + +#include <AEEStdLib.h> + +static inline void* mallocBrew(size_t n) +{ + // By default, memory allocated using MALLOC() is initialized + // to zero. This behavior can be disabled by performing a bitwise + // OR of the flag ALLOC_NO_ZMEM with the dwSize parameter. + return MALLOC(n | ALLOC_NO_ZMEM); +} + +static inline void* callocBrew(size_t numElements, size_t elementSize) +{ + return MALLOC(numElements * elementSize); +} + +static inline void freeBrew(void* p) +{ + return FREE(p); +} + +static inline void* reallocBrew(void* p, size_t n) +{ + return REALLOC(p, n | ALLOC_NO_ZMEM); +} + +// Use MALLOC macro instead of the standard malloc function. +// Although RVCT provides malloc, we can't use it in BREW +// because the loader does not initialize the base address properly. +#define malloc(n) mallocBrew(n) +#define calloc(n, s) callocBrew(n, s) +#define realloc(p, n) reallocBrew(p, n) +#define free(p) freeBrew(p) + +#endif // SystemMallocBrew_h diff --git a/JavaScriptCore/wtf/chromium/ChromiumThreading.h b/JavaScriptCore/wtf/chromium/ChromiumThreading.h index b2c5075..3938621 100644 --- a/JavaScriptCore/wtf/chromium/ChromiumThreading.h +++ b/JavaScriptCore/wtf/chromium/ChromiumThreading.h @@ -36,8 +36,7 @@ namespace WTF { // An interface to the embedding layer, which provides threading support. class ChromiumThreading { public: - static void initializeMainThread(); - static void scheduleDispatchFunctionsOnMainThread(); + static void callOnMainThread(void (*func)(void*), void* context); }; } // namespace WTF diff --git a/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp index 394370f..9e6592b 100644 --- a/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp +++ b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp @@ -31,18 +31,42 @@ #include "config.h" #include "MainThread.h" +#include "Assertions.h" #include "ChromiumThreading.h" +#include "Threading.h" namespace WTF { -void initializeMainThreadPlatform() +static ThreadIdentifier mainThreadIdentifier; + +void initializeMainThread() +{ + static bool initializedMainThread; + if (initializedMainThread) + return; + initializedMainThread = true; + + mainThreadIdentifier = currentThread(); +} + +void callOnMainThread(MainThreadFunction* function, void* context) +{ + ChromiumThreading::callOnMainThread(function, context); +} + +void callOnMainThreadAndWait(MainThreadFunction*, void*) +{ + ASSERT_NOT_REACHED(); +} + +void setMainThreadCallbacksPaused(bool) { - ChromiumThreading::initializeMainThread(); + ASSERT_NOT_REACHED(); } -void scheduleDispatchFunctionsOnMainThread() +bool isMainThread() { - ChromiumThreading::scheduleDispatchFunctionsOnMainThread(); + return currentThread() == mainThreadIdentifier; } } // namespace WTF diff --git a/JavaScriptCore/wtf/efl/MainThreadEfl.cpp b/JavaScriptCore/wtf/efl/MainThreadEfl.cpp new file mode 100644 index 0000000..fe32d1b --- /dev/null +++ b/JavaScriptCore/wtf/efl/MainThreadEfl.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * Copyright (C) 2008 Diego Gonzalez + * Copyright (C) 2008 Kenneth Rohde Christiansen + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 <Ecore.h> + +namespace WTF { + +void initializeMainThreadPlatform() +{ +} + +static int timeoutFired(void*) +{ + dispatchFunctionsFromMainThread(); + return ECORE_CALLBACK_CANCEL; +} + +void scheduleDispatchFunctionsOnMainThread() +{ + ecore_timer_add(0, timeoutFired, 0); +} + + +} diff --git a/JavaScriptCore/wtf/gtk/GOwnPtr.cpp b/JavaScriptCore/wtf/gobject/GOwnPtr.cpp index 1a151b9..da0d839 100644 --- a/JavaScriptCore/wtf/gtk/GOwnPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.cpp @@ -19,6 +19,7 @@ #include "config.h" #include "GOwnPtr.h" +#include <gio/gio.h> #include <glib.h> namespace WTF { @@ -57,4 +58,10 @@ template <> void freeOwnedGPtr<GDir>(GDir* ptr) if (ptr) g_dir_close(ptr); } + +template <> void freeOwnedGPtr<GFile>(GFile* ptr) +{ + if (ptr) + g_object_unref(ptr); +} } // namespace WTF diff --git a/JavaScriptCore/wtf/gtk/GOwnPtr.h b/JavaScriptCore/wtf/gobject/GOwnPtr.h index ad2c30e..1fc594c 100644 --- a/JavaScriptCore/wtf/gtk/GOwnPtr.h +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.h @@ -35,6 +35,7 @@ typedef struct _GMutex GMutex; typedef struct _GPatternSpec GPatternSpec; typedef struct _GDir GDir; typedef struct _GHashTable GHashTable; +typedef struct _GFile GFile; extern "C" void g_free(void*); namespace WTF { @@ -47,6 +48,7 @@ template<> void freeOwnedGPtr<GMutex>(GMutex*); template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*); template<> void freeOwnedGPtr<GDir>(GDir*); template<> void freeOwnedGPtr<GHashTable>(GHashTable*); +template<> void freeOwnedGPtr<GFile>(GFile*); template <typename T> class GOwnPtr : public Noncopyable { public: diff --git a/JavaScriptCore/wtf/gtk/GRefPtr.cpp b/JavaScriptCore/wtf/gobject/GRefPtr.cpp index e7cf34b..e7cf34b 100644 --- a/JavaScriptCore/wtf/gtk/GRefPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GRefPtr.cpp diff --git a/JavaScriptCore/wtf/gtk/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h index 66739ef..3a33605 100644 --- a/JavaScriptCore/wtf/gtk/GRefPtr.h +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -27,6 +27,9 @@ #include <algorithm> typedef struct _GHashTable GHashTable; +typedef void* gpointer; +extern "C" void g_object_unref(gpointer object); +extern "C" gpointer g_object_ref_sink(gpointer object); namespace WTF { diff --git a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp index a6ec8f7..0c5cf0c 100644 --- a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp +++ b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp @@ -44,8 +44,6 @@ namespace WTF { static Mutex* atomicallyInitializedStaticMutex; -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -62,8 +60,6 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); - mainThreadIdentifier = currentThread(); - initializeMainThread(); } } @@ -168,11 +164,6 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() -{ - return currentThread() == mainThreadIdentifier; -} - Mutex::Mutex() : m_mutex(g_mutex_new()) { diff --git a/JavaScriptCore/wtf/mac/MainThreadMac.mm b/JavaScriptCore/wtf/mac/MainThreadMac.mm index 0ddd5f6..17363bc 100644 --- a/JavaScriptCore/wtf/mac/MainThreadMac.mm +++ b/JavaScriptCore/wtf/mac/MainThreadMac.mm @@ -29,8 +29,11 @@ #import "config.h" #import "MainThread.h" +#import <CoreFoundation/CoreFoundation.h> #import <Foundation/NSThread.h> +#import <stdio.h> #import <wtf/Assertions.h> +#import <wtf/Threading.h> @interface WTFMainThreadCaller : NSObject { } @@ -48,28 +51,93 @@ namespace WTF { -static WTFMainThreadCaller* staticMainThreadCaller = nil; -#if USE(WEB_THREAD) -static NSThread* webThread = nil; -#endif +static WTFMainThreadCaller* staticMainThreadCaller; +static bool isTimerPosted; // This is only accessed on the 'main' thread. +static bool mainThreadEstablishedAsPthreadMain; +static pthread_t mainThreadPthread; +static NSThread* mainThreadNSThread; void initializeMainThreadPlatform() { +#if !defined(BUILDING_ON_TIGER) ASSERT(!staticMainThreadCaller); staticMainThreadCaller = [[WTFMainThreadCaller alloc] init]; -#if USE(WEB_THREAD) - webThread = [[NSThread currentThread] retain]; + mainThreadEstablishedAsPthreadMain = false; + mainThreadPthread = pthread_self(); + mainThreadNSThread = [[NSThread currentThread] retain]; +#else + ASSERT_NOT_REACHED(); #endif } +void initializeMainThreadToProcessMainThreadPlatform() +{ + if (!pthread_main_np()) + NSLog(@"WebKit Threading Violation - initial use of WebKit from a secondary thread."); + + ASSERT(!staticMainThreadCaller); + staticMainThreadCaller = [[WTFMainThreadCaller alloc] init]; + + mainThreadEstablishedAsPthreadMain = true; + mainThreadPthread = 0; + mainThreadNSThread = nil; +} + +static void timerFired(CFRunLoopTimerRef timer, void*) +{ + CFRelease(timer); + isTimerPosted = false; + WTF::dispatchFunctionsFromMainThread(); +} + +static void postTimer() +{ + ASSERT(isMainThread()); + + if (isTimerPosted) + return; + + isTimerPosted = true; + CFRunLoopAddTimer(CFRunLoopGetCurrent(), CFRunLoopTimerCreate(0, 0, 0, 0, 0, timerFired, 0), kCFRunLoopCommonModes); +} + void scheduleDispatchFunctionsOnMainThread() { ASSERT(staticMainThreadCaller); -#if USE(WEB_THREAD) - [staticMainThreadCaller performSelector:@selector(call) onThread:webThread withObject:nil waitUntilDone:NO]; + + if (isMainThread()) { + postTimer(); + return; + } + + if (mainThreadEstablishedAsPthreadMain) { + ASSERT(!mainThreadNSThread); + [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; + return; + } + +#if !defined(BUILDING_ON_TIGER) + ASSERT(mainThreadNSThread); + [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO]; +#else + ASSERT_NOT_REACHED(); +#endif +} + +bool isMainThread() +{ + if (mainThreadEstablishedAsPthreadMain) { + ASSERT(!mainThreadPthread); + return pthread_main_np(); + } + +#if !defined(BUILDING_ON_TIGER) + ASSERT(mainThreadPthread); + return pthread_equal(pthread_self(), mainThreadPthread); #else - [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; + ASSERT_NOT_REACHED(); + return false; #endif } diff --git a/JavaScriptCore/wtf/qt/MainThreadQt.cpp b/JavaScriptCore/wtf/qt/MainThreadQt.cpp index 7b2d0f2..98b6a0c 100644 --- a/JavaScriptCore/wtf/qt/MainThreadQt.cpp +++ b/JavaScriptCore/wtf/qt/MainThreadQt.cpp @@ -33,7 +33,7 @@ #include <QtCore/QObject> #include <QtCore/QCoreApplication> - +#include <QThread> namespace WTF { @@ -67,6 +67,11 @@ void scheduleDispatchFunctionsOnMainThread() QMetaObject::invokeMethod(webkit_main_thread_invoker(), "dispatch", Qt::QueuedConnection); } +bool isMainThread() +{ + return QThread::currentThread() == QCoreApplication::instance()->thread(); +} + } // namespace WTF #include "MainThreadQt.moc" diff --git a/JavaScriptCore/wtf/qt/StringQt.cpp b/JavaScriptCore/wtf/qt/StringQt.cpp new file mode 100644 index 0000000..b2c621a --- /dev/null +++ b/JavaScriptCore/wtf/qt/StringQt.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <wtf/text/WTFString.h> + +#include <QString> + +namespace WebCore { + +// String conversions +String::String(const QString& qstr) +{ + if (qstr.isNull()) + return; + m_impl = StringImpl::create(reinterpret_cast<const UChar*>(qstr.constData()), qstr.length()); +} + +String::String(const QStringRef& ref) +{ + if (!ref.string()) + return; + m_impl = StringImpl::create(reinterpret_cast<const UChar*>(ref.unicode()), ref.length()); +} + +String::operator QString() const +{ + return QString(reinterpret_cast<const QChar*>(characters()), length()); +} + +QDataStream& operator<<(QDataStream& stream, const String& str) +{ + // could be faster + stream << QString(str); + return stream; +} + +QDataStream& operator>>(QDataStream& stream, String& str) +{ + // mabe not the fastest way, but really easy + QString tmp; + stream >> tmp; + str = tmp; + return stream; +} + +} + +// vim: ts=4 sw=4 et diff --git a/JavaScriptCore/wtf/qt/ThreadingQt.cpp b/JavaScriptCore/wtf/qt/ThreadingQt.cpp index dc04a68..7f81646 100644 --- a/JavaScriptCore/wtf/qt/ThreadingQt.cpp +++ b/JavaScriptCore/wtf/qt/ThreadingQt.cpp @@ -84,8 +84,6 @@ public Q_SLOTS: static Mutex* atomicallyInitializedStaticMutex; -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -146,11 +144,6 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); - QThread* mainThread = QCoreApplication::instance()->thread(); - mainThreadIdentifier = identifierByQthreadHandle(mainThread); - if (!mainThreadIdentifier) - mainThreadIdentifier = establishIdentifierForThread(mainThread); - initializeMainThread(); } } @@ -215,11 +208,6 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() -{ - return QThread::currentThread() == QCoreApplication::instance()->thread(); -} - Mutex::Mutex() : m_mutex(new QMutex()) { diff --git a/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.cpp b/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.cpp new file mode 100644 index 0000000..6a28e9e --- /dev/null +++ b/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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" + +#if OS(SYMBIAN) + +#include "BlockAllocatorSymbian.h" + + +namespace WTF { + +/** Efficiently allocates blocks of size blockSize with blockSize alignment. + * Primarly designed for JSC Collector's needs. + * Not thread-safe. + */ +AlignedBlockAllocator::AlignedBlockAllocator(TUint32 reservationSize, TUint32 blockSize ) + : m_reservation(reservationSize), + m_blockSize(blockSize) +{ + + // Get system's page size value. + SYMBIAN_PAGESIZE(m_pageSize); + + // We only accept multiples of system page size for both initial reservation and the alignment/block size + m_reservation = SYMBIAN_ROUNDUPTOMULTIPLE(m_reservation, m_pageSize); + __ASSERT_ALWAYS(SYMBIAN_ROUNDUPTOMULTIPLE(m_blockSize, m_pageSize), User::Panic(_L("AlignedBlockAllocator1"), KErrArgument)); + + // Calculate max. bit flags we need to carve a reservationSize range into blockSize-sized blocks + m_map.numBits = m_reservation / m_blockSize; + const TUint32 bitsPerWord = 8*sizeof(TUint32); + const TUint32 numWords = (m_map.numBits + bitsPerWord -1) / bitsPerWord; + + m_map.bits = new TUint32[numWords]; + __ASSERT_ALWAYS(m_map.bits, User::Panic(_L("AlignedBlockAllocator2"), KErrNoMemory)); + m_map.clearAll(); + + // Open a Symbian RChunk, and reserve requested virtual address range + // Any thread in this process can operate this rchunk due to EOwnerProcess access rights. + TInt ret = m_chunk.CreateDisconnectedLocal(0 , 0, (TInt)m_reservation , EOwnerProcess); + if (ret != KErrNone) + User::Panic(_L("AlignedBlockAllocator3"), ret); + + // This is the offset to m_chunk.Base() required to make it m_blockSize-aligned + m_offset = SYMBIAN_ROUNDUPTOMULTIPLE(TUint32(m_chunk.Base()), m_blockSize) - TUint(m_chunk.Base()); + +} + +void* AlignedBlockAllocator::alloc() +{ + + TInt freeRam = 0; + void* address = 0; + + // Look up first free slot in bit map + const TInt freeIdx = m_map.findFree(); + + // Pseudo OOM: We ate up the address space we reserved.. + // ..even though the device may have free RAM left + if (freeIdx < 0) + return 0; + + TInt ret = m_chunk.Commit(m_offset + (m_blockSize * freeIdx), m_blockSize); + if (ret != KErrNone) + return 0; // True OOM: Device didn't have physical RAM to spare + + // Updated bit to mark region as in use. + m_map.set(freeIdx); + + // Calculate address of committed region (block) + address = (void*)( (m_chunk.Base() + m_offset) + (TUint)(m_blockSize * freeIdx) ); + + return address; +} + +void AlignedBlockAllocator::free(void* block) +{ + // Calculate index of block to be freed + TInt idx = TUint(static_cast<TUint8*>(block) - m_chunk.Base() - m_offset) / m_blockSize; + + __ASSERT_DEBUG(idx >= 0 && idx < m_map.numBits, User::Panic(_L("AlignedBlockAllocator4"), KErrCorrupt)); // valid index check + __ASSERT_DEBUG(m_map.get(idx), User::Panic(_L("AlignedBlockAllocator5"), KErrCorrupt)); // in-use flag check + + // Return committed region to system RAM pool (the physical RAM becomes usable by others) + TInt ret = m_chunk.Decommit(m_offset + m_blockSize * idx, m_blockSize); + + // mark this available again + m_map.clear(idx); +} + +void AlignedBlockAllocator::destroy() +{ + // release everything! + m_chunk.Decommit(0, m_chunk.MaxSize()); + m_map.clearAll(); +} + +AlignedBlockAllocator::~AlignedBlockAllocator() +{ + destroy(); + m_chunk.Close(); + delete [] m_map.bits; +} + +} // end of namespace + +#endif // SYMBIAN diff --git a/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.h b/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.h new file mode 100644 index 0000000..21422f6 --- /dev/null +++ b/JavaScriptCore/wtf/symbian/BlockAllocatorSymbian.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 BlockAllocatorSymbian_h +#define BlockAllocatorSymbian_h + +#include <e32cmn.h> +#include <e32std.h> +#include <hal.h> + + +#define SYMBIAN_PAGESIZE(x) (HAL::Get(HALData::EMemoryPageSize, x)); +#define SYMBIAN_FREERAM(x) (HAL::Get(HALData::EMemoryRAMFree, x)); +#define SYMBIAN_ROUNDUPTOMULTIPLE(x, multipleof) ( (x + multipleof - 1) & ~(multipleof - 1) ) + +// Set sane defaults if -D<flagname=value> wasn't provided via compiler args +#ifndef JSCCOLLECTOR_VIRTUALMEM_RESERVATION +#if defined(__WINS__) + // Emulator has limited virtual address space + #define JSCCOLLECTOR_VIRTUALMEM_RESERVATION (4*1024*1024) +#else + // HW has plenty of virtual addresses + #define JSCCOLLECTOR_VIRTUALMEM_RESERVATION (128*1024*1024) +#endif +#endif + +namespace WTF { + +/** + * Allocates contiguous region of size blockSize with blockSize-aligned address. + * blockSize must be a multiple of system page size (typically 4K on Symbian/ARM) + * + * @param reservationSize Virtual address range to be reserved upon creation of chunk (bytes). + * @param blockSize Size of a single allocation. Returned address will also be blockSize-aligned. + */ +class AlignedBlockAllocator { + public: + AlignedBlockAllocator(TUint32 reservationSize, TUint32 blockSize); + ~AlignedBlockAllocator(); + void destroy(); + void* alloc(); + void free(void* data); + + private: + RChunk m_chunk; // Symbian chunk that lets us reserve/commit/decommit + TUint m_offset; // offset of first committed region from base + TInt m_pageSize; // cached value of system page size, typically 4K on Symbian + TUint32 m_reservation; + TUint32 m_blockSize; + + // Tracks comitted/decommitted state of a blockSize region + struct { + + TUint32 *bits; // array of bit flags + TUint32 numBits; // number of regions to keep track of + + bool get(TUint32 n) const + { + return !!(bits[n >> 5] & (1 << (n & 0x1F))); + } + + void set(TUint32 n) + { + bits[n >> 5] |= (1 << (n & 0x1F)); + } + + void clear(TUint32 n) + { + bits[n >> 5] &= ~(1 << (n & 0x1F)); + } + + void clearAll() + { + for (TUint32 i = 0; i < numBits; i++) + clear(i); + } + + TInt findFree() const + { + for (TUint32 i = 0; i < numBits; i++) { + if (!get(i)) + return i; + } + return -1; + } + + } m_map; + +}; + +} + +#endif // end of BlockAllocatorSymbian_h + + diff --git a/JavaScriptCore/wtf/text/AtomicString.cpp b/JavaScriptCore/wtf/text/AtomicString.cpp new file mode 100644 index 0000000..ab52488 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicString.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple 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" + +#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC +#define ATOMICSTRING_HIDE_GLOBALS 1 +#endif + +#include "AtomicString.h" + +#include "StaticConstructors.h" +#include "StringHash.h" +#include <wtf/HashSet.h> +#include <wtf/Threading.h> +#include <wtf/WTFThreadData.h> + +namespace WebCore { + +class AtomicStringTable { +public: + static AtomicStringTable* create() + { + AtomicStringTable* table = new AtomicStringTable; + + WTFThreadData& data = wtfThreadData(); + data.m_atomicStringTable = table; + data.m_atomicStringTableDestructor = AtomicStringTable::destroy; + + return table; + } + + HashSet<StringImpl*>& table() + { + return m_table; + } + +private: + static void destroy(AtomicStringTable* table) + { + HashSet<StringImpl*>::iterator end = table->m_table.end(); + for (HashSet<StringImpl*>::iterator iter = table->m_table.begin(); iter != end; ++iter) + (*iter)->setIsAtomic(false); + delete table; + } + + HashSet<StringImpl*> m_table; +}; + +static inline HashSet<StringImpl*>& stringTable() +{ + // Once possible we should make this non-lazy (constructed in WTFThreadData's constructor). + AtomicStringTable* table = wtfThreadData().atomicStringTable(); + if (UNLIKELY(!table)) + table = AtomicStringTable::create(); + return table->table(); +} + +struct CStringTranslator { + static unsigned hash(const char* c) + { + return StringImpl::computeHash(c); + } + + static bool equal(StringImpl* r, const char* s) + { + int length = r->length(); + const UChar* d = r->characters(); + for (int i = 0; i != length; ++i) { + unsigned char c = s[i]; + if (d[i] != c) + return false; + } + return s[length] == 0; + } + + static void translate(StringImpl*& location, const char* const& c, unsigned hash) + { + location = StringImpl::create(c).releaseRef(); + location->setHash(hash); + location->setIsAtomic(true); + } +}; + +bool operator==(const AtomicString& a, const char* b) +{ + StringImpl* impl = a.impl(); + if ((!impl || !impl->characters()) && !b) + return true; + if ((!impl || !impl->characters()) || !b) + return false; + return CStringTranslator::equal(impl, b); +} + +PassRefPtr<StringImpl> AtomicString::add(const char* c) +{ + if (!c) + return 0; + if (!*c) + return StringImpl::empty(); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<const char*, CStringTranslator>(c); + if (!addResult.second) + return *addResult.first; + return adoptRef(*addResult.first); +} + +struct UCharBuffer { + const UChar* s; + unsigned length; +}; + +static inline bool equal(StringImpl* string, const UChar* characters, unsigned length) +{ + if (string->length() != length) + return false; + + // FIXME: perhaps we should have a more abstract macro that indicates when + // going 4 bytes at a time is unsafe +#if CPU(ARM) || CPU(SH4) + const UChar* stringCharacters = string->characters(); + for (unsigned i = 0; i != length; ++i) { + if (*stringCharacters++ != *characters++) + return false; + } + return true; +#else + /* Do it 4-bytes-at-a-time on architectures where it's safe */ + + const uint32_t* stringCharacters = reinterpret_cast<const uint32_t*>(string->characters()); + const uint32_t* bufferCharacters = reinterpret_cast<const uint32_t*>(characters); + + unsigned halfLength = length >> 1; + for (unsigned i = 0; i != halfLength; ++i) { + if (*stringCharacters++ != *bufferCharacters++) + return false; + } + + if (length & 1 && *reinterpret_cast<const uint16_t*>(stringCharacters) != *reinterpret_cast<const uint16_t*>(bufferCharacters)) + return false; + + return true; +#endif +} + +struct UCharBufferTranslator { + static unsigned hash(const UCharBuffer& buf) + { + return StringImpl::computeHash(buf.s, buf.length); + } + + static bool equal(StringImpl* const& str, const UCharBuffer& buf) + { + return WebCore::equal(str, buf.s, buf.length); + } + + static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash) + { + location = StringImpl::create(buf.s, buf.length).releaseRef(); + location->setHash(hash); + location->setIsAtomic(true); + } +}; + +struct HashAndCharacters { + unsigned hash; + const UChar* characters; + unsigned length; +}; + +struct HashAndCharactersTranslator { + static unsigned hash(const HashAndCharacters& buffer) + { + ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.length)); + return buffer.hash; + } + + static bool equal(StringImpl* const& string, const HashAndCharacters& buffer) + { + return WebCore::equal(string, buffer.characters, buffer.length); + } + + static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash) + { + location = StringImpl::create(buffer.characters, buffer.length).releaseRef(); + location->setHash(hash); + location->setIsAtomic(true); + } +}; + +PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length) +{ + if (!s) + return 0; + + if (length == 0) + return StringImpl::empty(); + + UCharBuffer buf = { s, length }; + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf); + + // If the string is newly-translated, then we need to adopt it. + // The boolean in the pair tells us if that is so. + return addResult.second ? adoptRef(*addResult.first) : *addResult.first; +} + +PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsigned existingHash) +{ + ASSERT(s); + ASSERT(existingHash); + + if (length == 0) + return StringImpl::empty(); + + HashAndCharacters buffer = { existingHash, s, length }; + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer); + if (!addResult.second) + return *addResult.first; + return adoptRef(*addResult.first); +} + +PassRefPtr<StringImpl> AtomicString::add(const UChar* s) +{ + if (!s) + return 0; + + int length = 0; + while (s[length] != UChar(0)) + length++; + + if (length == 0) + return StringImpl::empty(); + + UCharBuffer buf = {s, length}; + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf); + + // If the string is newly-translated, then we need to adopt it. + // The boolean in the pair tells us if that is so. + return addResult.second ? adoptRef(*addResult.first) : *addResult.first; +} + +PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) +{ + if (!r || r->isAtomic()) + return r; + + if (r->length() == 0) + return StringImpl::empty(); + + StringImpl* result = *stringTable().add(r).first; + if (result == r) + r->setIsAtomic(true); + return result; +} + +AtomicStringImpl* AtomicString::find(const UChar* s, unsigned length, unsigned existingHash) +{ + ASSERT(s); + ASSERT(existingHash); + + if (length == 0) + return static_cast<AtomicStringImpl*>(StringImpl::empty()); + + HashAndCharacters buffer = { existingHash, s, length }; + HashSet<StringImpl*>::iterator iterator = stringTable().find<HashAndCharacters, HashAndCharactersTranslator>(buffer); + if (iterator == stringTable().end()) + return 0; + return static_cast<AtomicStringImpl*>(*iterator); +} + +void AtomicString::remove(StringImpl* r) +{ + stringTable().remove(r); +} + +AtomicString AtomicString::lower() const +{ + // Note: This is a hot function in the Dromaeo benchmark. + StringImpl* impl = this->impl(); + RefPtr<StringImpl> newImpl = impl->lower(); + if (LIKELY(newImpl == impl)) + return *this; + return AtomicString(newImpl); +} + +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, nullAtom) +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, emptyAtom, "") +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, textAtom, "#text") +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, commentAtom, "#comment") +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, starAtom, "*") +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, xmlAtom, "xml") +JS_EXPORTDATA DEFINE_GLOBAL(AtomicString, xmlnsAtom, "xmlns") + +void AtomicString::init() +{ + static bool initialized; + if (!initialized) { + // Initialization is not thread safe, so this function must be called from the main thread first. + ASSERT(isMainThread()); + + // Use placement new to initialize the globals. + new ((void*)&nullAtom) AtomicString; + new ((void*)&emptyAtom) AtomicString(""); + new ((void*)&textAtom) AtomicString("#text"); + new ((void*)&commentAtom) AtomicString("#comment"); + new ((void*)&starAtom) AtomicString("*"); + new ((void*)&xmlAtom) AtomicString("xml"); + new ((void*)&xmlnsAtom) AtomicString("xmlns"); + + initialized = true; + } +} + +} diff --git a/JavaScriptCore/wtf/text/AtomicString.h b/JavaScriptCore/wtf/text/AtomicString.h new file mode 100644 index 0000000..9db70f4 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicString.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008 Apple 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 AtomicString_h +#define AtomicString_h + +#include "AtomicStringImpl.h" +#include "WTFString.h" + +// Define 'NO_IMPLICIT_ATOMICSTRING' before including this header, +// to disallow (expensive) implicit String-->AtomicString conversions. +#ifdef NO_IMPLICIT_ATOMICSTRING +#define ATOMICSTRING_CONVERSION explicit +#else +#define ATOMICSTRING_CONVERSION +#endif + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace WebCore { + +struct AtomicStringHash; + +class AtomicString : public FastAllocBase { +public: + static void init(); + + AtomicString() { } + AtomicString(const char* s) : m_string(add(s)) { } + AtomicString(const UChar* s, unsigned length) : m_string(add(s, length)) { } + AtomicString(const UChar* s, unsigned length, unsigned existingHash) : m_string(add(s, length, existingHash)) { } + AtomicString(const UChar* s) : m_string(add(s)) { } + ATOMICSTRING_CONVERSION AtomicString(StringImpl* imp) : m_string(add(imp)) { } + AtomicString(AtomicStringImpl* imp) : m_string(imp) { } + ATOMICSTRING_CONVERSION AtomicString(const String& s) : m_string(add(s.impl())) { } + + // Hash table deleted values, which are only constructed and never copied or destroyed. + AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { } + bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); } + + static AtomicStringImpl* find(const UChar* s, unsigned length, unsigned existingHash); + + operator const String&() const { return m_string; } + const String& string() const { return m_string; }; + + AtomicStringImpl* impl() const { return static_cast<AtomicStringImpl *>(m_string.impl()); } + + const UChar* characters() const { return m_string.characters(); } + unsigned length() const { return m_string.length(); } + + UChar operator[](unsigned int i) const { return m_string[i]; } + + bool contains(UChar c) const { return m_string.contains(c); } + bool contains(const char* s, bool caseSensitive = true) const + { return m_string.contains(s, caseSensitive); } + bool contains(const String& s, bool caseSensitive = true) const + { return m_string.contains(s, caseSensitive); } + + int find(UChar c, int start = 0) const { return m_string.find(c, start); } + int find(const char* s, int start = 0, bool caseSentitive = true) const + { return m_string.find(s, start, caseSentitive); } + int find(const String& s, int start = 0, bool caseSentitive = true) const + { return m_string.find(s, start, caseSentitive); } + + bool startsWith(const String& s, bool caseSensitive = true) const + { return m_string.startsWith(s, caseSensitive); } + bool endsWith(const String& s, bool caseSensitive = true) const + { return m_string.endsWith(s, caseSensitive); } + + AtomicString lower() const; + AtomicString upper() const { return AtomicString(impl()->upper()); } + + int toInt(bool* ok = 0) const { return m_string.toInt(ok); } + double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); } + float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); } + bool percentage(int& p) const { return m_string.percentage(p); } + + bool isNull() const { return m_string.isNull(); } + bool isEmpty() const { return m_string.isEmpty(); } + + static void remove(StringImpl*); + +#if PLATFORM(CF) + AtomicString(CFStringRef s) : m_string(add(String(s).impl())) { } + CFStringRef createCFString() const { return m_string.createCFString(); } +#endif +#ifdef __OBJC__ + AtomicString(NSString* s) : m_string(add(String(s).impl())) { } + operator NSString*() const { return m_string; } +#endif +#if PLATFORM(QT) + AtomicString(const QString& s) : m_string(add(String(s).impl())) { } + operator QString() const { return m_string; } +#endif + +private: + String m_string; + + static PassRefPtr<StringImpl> add(const char*); + static PassRefPtr<StringImpl> add(const UChar*, unsigned length); + static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash); + static PassRefPtr<StringImpl> add(const UChar*); + static PassRefPtr<StringImpl> add(StringImpl*); +}; + +inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } +bool operator==(const AtomicString& a, const char* b); +inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); } +inline bool operator==(const char* a, const AtomicString& b) { return b == a; } +inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); } + +inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); } +inline bool operator!=(const AtomicString& a, const char *b) { return !(a == b); } +inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); } +inline bool operator!=(const char* a, const AtomicString& b) { return !(b == a); } +inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); } + +inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } +inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), b); } +inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); } +inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); } +inline bool equalIgnoringCase(const String& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } + +// Define external global variables for the commonly used atomic strings. +// These are only usable from the main thread. +#ifndef ATOMICSTRING_HIDE_GLOBALS + extern const JS_EXPORTDATA AtomicString nullAtom; + extern const JS_EXPORTDATA AtomicString emptyAtom; + extern const JS_EXPORTDATA AtomicString textAtom; + extern const JS_EXPORTDATA AtomicString commentAtom; + extern const JS_EXPORTDATA AtomicString starAtom; + extern const JS_EXPORTDATA AtomicString xmlAtom; + extern const JS_EXPORTDATA AtomicString xmlnsAtom; +#endif + +} // namespace WebCore + + +namespace WTF { + + // AtomicStringHash is the default hash for AtomicString + template<typename T> struct DefaultHash; + template<> struct DefaultHash<WebCore::AtomicString> { + typedef WebCore::AtomicStringHash Hash; + }; + +} // namespace WTF + +#endif // AtomicString_h diff --git a/JavaScriptCore/wtf/text/AtomicStringImpl.h b/JavaScriptCore/wtf/text/AtomicStringImpl.h new file mode 100644 index 0000000..4b813f8 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicStringImpl.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * 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 AtomicStringImpl_h +#define AtomicStringImpl_h + +#include "StringImpl.h" + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace WebCore { + +class AtomicStringImpl : public StringImpl +{ +public: + AtomicStringImpl() : StringImpl(0) {} +}; + +} + +#endif diff --git a/JavaScriptCore/wtf/text/CString.cpp b/JavaScriptCore/wtf/text/CString.cpp new file mode 100644 index 0000000..d93a5a3 --- /dev/null +++ b/JavaScriptCore/wtf/text/CString.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2003, 2006, 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "CString.h" + +using std::min; + +namespace WTF { + +CString::CString(const char* str) +{ + init(str, strlen(str)); +} + +CString::CString(const char* str, unsigned length) +{ + init(str, length); +} + +void CString::init(const char* str, unsigned length) +{ + if (!str) + return; + + m_buffer = CStringBuffer::create(length + 1); + memcpy(m_buffer->mutableData(), str, length); + m_buffer->mutableData()[length] = '\0'; +} + +const char* CString::data() const +{ + return m_buffer ? m_buffer->data() : 0; +} + +char* CString::mutableData() +{ + copyBufferIfNeeded(); + if (!m_buffer) + return 0; + return m_buffer->mutableData(); +} + +unsigned CString::length() const +{ + return m_buffer ? m_buffer->length() - 1 : 0; +} + +CString CString::newUninitialized(size_t length, char*& characterBuffer) +{ + CString result; + result.m_buffer = CStringBuffer::create(length + 1); + char* bytes = result.m_buffer->mutableData(); + bytes[length] = '\0'; + characterBuffer = bytes; + return result; +} + +void CString::copyBufferIfNeeded() +{ + if (!m_buffer || m_buffer->hasOneRef()) + return; + + int len = m_buffer->length(); + RefPtr<CStringBuffer> m_temp = m_buffer; + m_buffer = CStringBuffer::create(len); + memcpy(m_buffer->mutableData(), m_temp->data(), len); +} + +bool operator==(const CString& a, const CString& b) +{ + if (a.isNull() != b.isNull()) + return false; + if (a.length() != b.length()) + return false; + return !strncmp(a.data(), b.data(), min(a.length(), b.length())); +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/text/CString.h b/JavaScriptCore/wtf/text/CString.h new file mode 100644 index 0000000..47f7675 --- /dev/null +++ b/JavaScriptCore/wtf/text/CString.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2003, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CString_h +#define CString_h + +#include "PassRefPtr.h" +#include "RefCounted.h" +#include "Vector.h" + +namespace WTF { + +class CStringBuffer : public RefCounted<CStringBuffer> { +public: + const char* data() { return m_vector.data(); } + size_t length() { return m_vector.size(); } + +private: + friend class CString; + + static PassRefPtr<CStringBuffer> create(unsigned length) { return adoptRef(new CStringBuffer(length)); } + CStringBuffer(unsigned length) : m_vector(length) { } + char* mutableData() { return m_vector.data(); } + + Vector<char> m_vector; +}; + +// A container for a null-terminated char array supporting copy-on-write +// assignment. The contained char array may be null. +class CString { +public: + CString() { } + CString(const char*); + CString(const char*, unsigned length); + CString(CStringBuffer* buffer) : m_buffer(buffer) { } + static CString newUninitialized(size_t length, char*& characterBuffer); + + const char* data() const; + char* mutableData(); + unsigned length() const; + + bool isNull() const { return !m_buffer; } + + CStringBuffer* buffer() const { return m_buffer.get(); } + +private: + void copyBufferIfNeeded(); + void init(const char*, unsigned length); + RefPtr<CStringBuffer> m_buffer; +}; + +bool operator==(const CString& a, const CString& b); +inline bool operator!=(const CString& a, const CString& b) { return !(a == b); } + +} // namespace WTF + +using WTF::CString; + +#endif // CString_h diff --git a/JavaScriptCore/wtf/text/StringBuffer.h b/JavaScriptCore/wtf/text/StringBuffer.h new file mode 100644 index 0000000..353a44a --- /dev/null +++ b/JavaScriptCore/wtf/text/StringBuffer.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 StringBuffer_h +#define StringBuffer_h + +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class StringBuffer : public Noncopyable { +public: + explicit StringBuffer(unsigned length) + : m_length(length) + , m_data(static_cast<UChar*>(fastMalloc(length * sizeof(UChar)))) + { + } + ~StringBuffer() + { + fastFree(m_data); + } + + void shrink(unsigned newLength) + { + ASSERT(newLength <= m_length); + m_length = newLength; + } + + void resize(unsigned newLength) + { + if (newLength > m_length) + m_data = static_cast<UChar*>(fastRealloc(m_data, newLength * sizeof(UChar))); + m_length = newLength; + } + + unsigned length() const { return m_length; } + UChar* characters() { return m_data; } + + UChar& operator[](unsigned i) { ASSERT(i < m_length); return m_data[i]; } + + UChar* release() { UChar* data = m_data; m_data = 0; return data; } + +private: + unsigned m_length; + UChar* m_data; +}; + +} + +#endif diff --git a/JavaScriptCore/wtf/text/StringHash.h b/JavaScriptCore/wtf/text/StringHash.h new file mode 100644 index 0000000..b820004 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringHash.h @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved + * Copyright (C) Research In Motion Limited 2009. 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 StringHash_h +#define StringHash_h + +#include "AtomicString.h" +#include "WTFString.h" +#include <wtf/HashTraits.h> +#include <wtf/StringHashFunctions.h> +#include <wtf/unicode/Unicode.h> + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace WebCore { + + // The hash() functions on StringHash and CaseFoldingHash do not support + // null strings. get(), contains(), and add() on HashMap<String,..., StringHash> + // cause a null-pointer dereference when passed null strings. + + // FIXME: We should really figure out a way to put the computeHash function that's + // currently a member function of StringImpl into this file so we can be a little + // closer to having all the nearly-identical hash functions in one place. + + struct StringHash { + static unsigned hash(StringImpl* key) { return key->hash(); } + static bool equal(const StringImpl* a, const StringImpl* b) + { + if (a == b) + return true; + if (!a || !b) + return false; + + unsigned aLength = a->length(); + unsigned bLength = b->length(); + if (aLength != bLength) + return false; + + // FIXME: perhaps we should have a more abstract macro that indicates when + // going 4 bytes at a time is unsafe +#if CPU(ARM) || CPU(SH4) + const UChar* aChars = a->characters(); + const UChar* bChars = b->characters(); + for (unsigned i = 0; i != aLength; ++i) { + if (*aChars++ != *bChars++) + return false; + } + return true; +#else + /* Do it 4-bytes-at-a-time on architectures where it's safe */ + const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters()); + const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters()); + + unsigned halfLength = aLength >> 1; + for (unsigned i = 0; i != halfLength; ++i) + if (*aChars++ != *bChars++) + return false; + + if (aLength & 1 && *reinterpret_cast<const uint16_t*>(aChars) != *reinterpret_cast<const uint16_t*>(bChars)) + return false; + + return true; +#endif + } + + static unsigned hash(const RefPtr<StringImpl>& key) { return key->hash(); } + static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b) + { + return equal(a.get(), b.get()); + } + + static unsigned hash(const String& key) { return key.impl()->hash(); } + static bool equal(const String& a, const String& b) + { + return equal(a.impl(), b.impl()); + } + + static const bool safeToCompareToEmptyOrDeleted = false; + }; + + class CaseFoldingHash { + public: + // Paul Hsieh's SuperFastHash + // http://www.azillionmonkeys.com/qed/hash.html + static unsigned hash(const UChar* data, unsigned length) + { + unsigned l = length; + const UChar* s = data; + uint32_t hash = WTF::stringHashingStartValue; + uint32_t tmp; + + int rem = l & 1; + l >>= 1; + + // Main loop. + for (; l > 0; l--) { + hash += WTF::Unicode::foldCase(s[0]); + tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + s += 2; + hash += hash >> 11; + } + + // Handle end case. + if (rem) { + hash += WTF::Unicode::foldCase(s[0]); + hash ^= hash << 11; + hash += hash >> 17; + } + + // Force "avalanching" of final 127 bits. + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 2; + hash += hash >> 15; + hash ^= hash << 10; + + // This avoids ever returning a hash code of 0, since that is used to + // signal "hash not computed yet", using a value that is likely to be + // effectively the same as 0 when the low bits are masked. + hash |= !hash << 31; + + return hash; + } + + static unsigned hash(StringImpl* str) + { + return hash(str->characters(), str->length()); + } + + static unsigned hash(const char* str, unsigned length) + { + // This hash is designed to work on 16-bit chunks at a time. But since the normal case + // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they + // were 16-bit chunks, which will give matching results. + + unsigned l = length; + const char* s = str; + uint32_t hash = WTF::stringHashingStartValue; + uint32_t tmp; + + int rem = l & 1; + l >>= 1; + + // Main loop + for (; l > 0; l--) { + hash += WTF::Unicode::foldCase(s[0]); + tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + s += 2; + hash += hash >> 11; + } + + // Handle end case + if (rem) { + hash += WTF::Unicode::foldCase(s[0]); + hash ^= hash << 11; + hash += hash >> 17; + } + + // Force "avalanching" of final 127 bits + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 2; + hash += hash >> 15; + hash ^= hash << 10; + + // this avoids ever returning a hash code of 0, since that is used to + // signal "hash not computed yet", using a value that is likely to be + // effectively the same as 0 when the low bits are masked + hash |= !hash << 31; + + return hash; + } + + static bool equal(const StringImpl* a, const StringImpl* b) + { + if (a == b) + return true; + if (!a || !b) + return false; + unsigned length = a->length(); + if (length != b->length()) + return false; + return WTF::Unicode::umemcasecmp(a->characters(), b->characters(), length) == 0; + } + + static unsigned hash(const RefPtr<StringImpl>& key) + { + return hash(key.get()); + } + + static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b) + { + return equal(a.get(), b.get()); + } + + static unsigned hash(const String& key) + { + return hash(key.impl()); + } + static unsigned hash(const AtomicString& key) + { + return hash(key.impl()); + } + static bool equal(const String& a, const String& b) + { + return equal(a.impl(), b.impl()); + } + static bool equal(const AtomicString& a, const AtomicString& b) + { + return (a == b) || equal(a.impl(), b.impl()); + } + + static const bool safeToCompareToEmptyOrDeleted = false; + }; + + // This hash can be used in cases where the key is a hash of a string, but we don't + // want to store the string. It's not really specific to string hashing, but all our + // current uses of it are for strings. + struct AlreadyHashed : IntHash<unsigned> { + static unsigned hash(unsigned key) { return key; } + + // To use a hash value as a key for a hash table, we need to eliminate the + // "deleted" value, which is negative one. That could be done by changing + // the string hash function to never generate negative one, but this works + // and is still relatively efficient. + static unsigned avoidDeletedValue(unsigned hash) + { + ASSERT(hash); + unsigned newHash = hash | (!(hash + 1) << 31); + ASSERT(newHash); + ASSERT(newHash != 0xFFFFFFFF); + return newHash; + } + }; + +} + +namespace WTF { + + template<> struct HashTraits<WebCore::String> : GenericHashTraits<WebCore::String> { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(WebCore::String& slot) { new (&slot) WebCore::String(HashTableDeletedValue); } + static bool isDeletedValue(const WebCore::String& slot) { return slot.isHashTableDeletedValue(); } + }; + +} + +#endif diff --git a/JavaScriptCore/wtf/text/StringImpl.cpp b/JavaScriptCore/wtf/text/StringImpl.cpp new file mode 100644 index 0000000..ff69737 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringImpl.cpp @@ -0,0 +1,953 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller ( mueller@kde.org ) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) + * + * 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 "StringImpl.h" + +#include "AtomicString.h" +#include "StringBuffer.h" +#include "StringHash.h" +#include <wtf/StdLibExtras.h> +#include <wtf/WTFThreadData.h> + +using namespace WTF; +using namespace Unicode; + +namespace WebCore { + +static const unsigned minLengthToShare = 20; + +StringImpl::~StringImpl() +{ + ASSERT(!isStatic()); + + if (isAtomic()) + AtomicString::remove(this); +#if USE(JSC) + if (isIdentifier()) + wtfThreadData().currentIdentifierTable()->remove(this); +#endif + + BufferOwnership ownership = bufferOwnership(); + if (ownership != BufferInternal) { + if (ownership == BufferOwned) { + ASSERT(!m_sharedBuffer); + ASSERT(m_data); + fastFree(const_cast<UChar*>(m_data)); + } else if (ownership == BufferSubstring) { + ASSERT(m_substringBuffer); + m_substringBuffer->deref(); + } else { + ASSERT(ownership == BufferShared); + ASSERT(m_sharedBuffer); + m_sharedBuffer->deref(); + } + } +} + +StringImpl* StringImpl::empty() +{ + // FIXME: This works around a bug in our port of PCRE, that a regular expression + // run on the empty string may still perform a read from the first element, and + // as such we need this to be a valid pointer. No code should ever be reading + // from a zero length string, so this should be able to be a non-null pointer + // into the zero-page. + // Replace this with 'reinterpret_cast<UChar*>(static_cast<intptr_t>(1))' once + // PCRE goes away. + static UChar emptyUCharData = 0; + DEFINE_STATIC_LOCAL(StringImpl, emptyString, (&emptyUCharData, 0, ConstructStaticString)); + return &emptyString; +} + +PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data) +{ + if (!length) { + data = 0; + return empty(); + } + + // Allocate a single buffer large enough to contain the StringImpl + // struct as well as the data which it contains. This removes one + // heap allocation from this call. + if (length > ((std::numeric_limits<size_t>::max() - sizeof(StringImpl)) / sizeof(UChar))) + CRASH(); + size_t size = sizeof(StringImpl) + length * sizeof(UChar); + StringImpl* string = static_cast<StringImpl*>(fastMalloc(size)); + + data = reinterpret_cast<UChar*>(string + 1); + return adoptRef(new (string) StringImpl(length)); +} + +PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length) +{ + if (!characters || !length) + return empty(); + + UChar* data; + PassRefPtr<StringImpl> string = createUninitialized(length, data); + memcpy(data, characters, length * sizeof(UChar)); + return string; +} + +PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length) +{ + if (!characters || !length) + return empty(); + + UChar* data; + PassRefPtr<StringImpl> string = createUninitialized(length, data); + for (unsigned i = 0; i != length; ++i) { + unsigned char c = characters[i]; + data[i] = c; + } + return string; +} + +PassRefPtr<StringImpl> StringImpl::create(const char* string) +{ + if (!string) + return empty(); + return create(string, strlen(string)); +} + +PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) +{ + ASSERT(characters); + ASSERT(minLengthToShare && length >= minLengthToShare); + return adoptRef(new StringImpl(characters, length, sharedBuffer)); +} + +SharedUChar* StringImpl::sharedBuffer() +{ + if (m_length < minLengthToShare) + return 0; + // All static strings are smaller that the minimim length to share. + ASSERT(!isStatic()); + + BufferOwnership ownership = bufferOwnership(); + + if (ownership == BufferInternal) + return 0; + if (ownership == BufferSubstring) + return m_substringBuffer->sharedBuffer(); + if (ownership == BufferOwned) { + ASSERT(!m_sharedBuffer); + m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).releaseRef(); + m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; + } + + ASSERT(bufferOwnership() == BufferShared); + ASSERT(m_sharedBuffer); + return m_sharedBuffer; +} + +bool StringImpl::containsOnlyWhitespace() +{ + // FIXME: The definition of whitespace here includes a number of characters + // that are not whitespace from the point of view of RenderText; I wonder if + // that's a problem in practice. + for (unsigned i = 0; i < m_length; i++) + if (!isASCIISpace(m_data[i])) + return false; + return true; +} + +PassRefPtr<StringImpl> StringImpl::substring(unsigned start, unsigned length) +{ + if (start >= m_length) + return empty(); + unsigned maxLength = m_length - start; + if (length >= maxLength) { + if (!start) + return this; + length = maxLength; + } + return create(m_data + start, length); +} + +UChar32 StringImpl::characterStartingAt(unsigned i) +{ + if (U16_IS_SINGLE(m_data[i])) + return m_data[i]; + if (i + 1 < m_length && U16_IS_LEAD(m_data[i]) && U16_IS_TRAIL(m_data[i + 1])) + return U16_GET_SUPPLEMENTARY(m_data[i], m_data[i + 1]); + return 0; +} + +PassRefPtr<StringImpl> StringImpl::lower() +{ + // Note: This is a hot function in the Dromaeo benchmark, specifically the + // no-op code path up through the first 'return' statement. + + // First scan the string for uppercase and non-ASCII characters: + UChar ored = 0; + bool noUpper = true; + const UChar *end = m_data + m_length; + for (const UChar* chp = m_data; chp != end; chp++) { + if (UNLIKELY(isASCIIUpper(*chp))) + noUpper = false; + ored |= *chp; + } + + // Nothing to do if the string is all ASCII with no uppercase. + if (noUpper && !(ored & ~0x7F)) + return this; + + int32_t length = m_length; + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + if (!(ored & ~0x7F)) { + // Do a faster loop for the case where all the characters are ASCII. + for (int i = 0; i < length; i++) { + UChar c = m_data[i]; + data[i] = toASCIILower(c); + } + return newImpl; + } + + // Do a slower implementation for cases that include non-ASCII characters. + bool error; + int32_t realLength = Unicode::toLower(data, length, m_data, m_length, &error); + if (!error && realLength == length) + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::toLower(data, realLength, m_data, m_length, &error); + if (error) + return this; + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::upper() +{ + // This function could be optimized for no-op cases the way lower() is, + // but in empirical testing, few actual calls to upper() are no-ops, so + // it wouldn't be worth the extra time for pre-scanning. + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + int32_t length = m_length; + + // Do a faster loop for the case where all the characters are ASCII. + UChar ored = 0; + for (int i = 0; i < length; i++) { + UChar c = m_data[i]; + ored |= c; + data[i] = toASCIIUpper(c); + } + if (!(ored & ~0x7F)) + return newImpl; + + // Do a slower implementation for cases that include non-ASCII characters. + bool error; + int32_t realLength = Unicode::toUpper(data, length, m_data, m_length, &error); + if (!error && realLength == length) + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::toUpper(data, realLength, m_data, m_length, &error); + if (error) + return this; + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::secure(UChar aChar) +{ + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + int32_t length = m_length; + for (int i = 0; i < length; ++i) + data[i] = aChar; + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::foldCase() +{ + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + int32_t length = m_length; + + // Do a faster loop for the case where all the characters are ASCII. + UChar ored = 0; + for (int i = 0; i < length; i++) { + UChar c = m_data[i]; + ored |= c; + data[i] = toASCIILower(c); + } + if (!(ored & ~0x7F)) + return newImpl; + + // Do a slower implementation for cases that include non-ASCII characters. + bool error; + int32_t realLength = Unicode::foldCase(data, length, m_data, m_length, &error); + if (!error && realLength == length) + return newImpl; + newImpl = createUninitialized(realLength, data); + Unicode::foldCase(data, realLength, m_data, m_length, &error); + if (error) + return this; + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::stripWhiteSpace() +{ + if (!m_length) + return empty(); + + unsigned start = 0; + unsigned end = m_length - 1; + + // skip white space from start + while (start <= end && isSpaceOrNewline(m_data[start])) + start++; + + // only white space + if (start > end) + return empty(); + + // skip white space from end + while (end && isSpaceOrNewline(m_data[end])) + end--; + + if (!start && end == m_length - 1) + return this; + return create(m_data + start, end + 1 - start); +} + +PassRefPtr<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr findMatch) +{ + const UChar* from = m_data; + const UChar* fromend = from + m_length; + + // Assume the common case will not remove any characters + while (from != fromend && !findMatch(*from)) + from++; + if (from == fromend) + return this; + + StringBuffer data(m_length); + UChar* to = data.characters(); + unsigned outc = from - m_data; + + if (outc) + memcpy(to, m_data, outc * sizeof(UChar)); + + while (true) { + while (from != fromend && findMatch(*from)) + from++; + while (from != fromend && !findMatch(*from)) + to[outc++] = *from++; + if (from == fromend) + break; + } + + data.shrink(outc); + + return adopt(data); +} + +PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace() +{ + StringBuffer data(m_length); + + const UChar* from = m_data; + const UChar* fromend = from + m_length; + int outc = 0; + bool changedToSpace = false; + + UChar* to = data.characters(); + + while (true) { + while (from != fromend && isSpaceOrNewline(*from)) { + if (*from != ' ') + changedToSpace = true; + from++; + } + while (from != fromend && !isSpaceOrNewline(*from)) + to[outc++] = *from++; + if (from != fromend) + to[outc++] = ' '; + else + break; + } + + if (outc > 0 && to[outc - 1] == ' ') + outc--; + + if (static_cast<unsigned>(outc) == m_length && !changedToSpace) + return this; + + data.shrink(outc); + + return adopt(data); +} + +int StringImpl::toIntStrict(bool* ok, int base) +{ + return charactersToIntStrict(m_data, m_length, ok, base); +} + +unsigned StringImpl::toUIntStrict(bool* ok, int base) +{ + return charactersToUIntStrict(m_data, m_length, ok, base); +} + +int64_t StringImpl::toInt64Strict(bool* ok, int base) +{ + return charactersToInt64Strict(m_data, m_length, ok, base); +} + +uint64_t StringImpl::toUInt64Strict(bool* ok, int base) +{ + return charactersToUInt64Strict(m_data, m_length, ok, base); +} + +intptr_t StringImpl::toIntPtrStrict(bool* ok, int base) +{ + return charactersToIntPtrStrict(m_data, m_length, ok, base); +} + +int StringImpl::toInt(bool* ok) +{ + return charactersToInt(m_data, m_length, ok); +} + +unsigned StringImpl::toUInt(bool* ok) +{ + return charactersToUInt(m_data, m_length, ok); +} + +int64_t StringImpl::toInt64(bool* ok) +{ + return charactersToInt64(m_data, m_length, ok); +} + +uint64_t StringImpl::toUInt64(bool* ok) +{ + return charactersToUInt64(m_data, m_length, ok); +} + +intptr_t StringImpl::toIntPtr(bool* ok) +{ + return charactersToIntPtr(m_data, m_length, ok); +} + +double StringImpl::toDouble(bool* ok) +{ + return charactersToDouble(m_data, m_length, ok); +} + +float StringImpl::toFloat(bool* ok) +{ + return charactersToFloat(m_data, m_length, ok); +} + +static bool equal(const UChar* a, const char* b, int length) +{ + ASSERT(length >= 0); + while (length--) { + unsigned char bc = *b++; + if (*a++ != bc) + return false; + } + return true; +} + +bool equalIgnoringCase(const UChar* a, const char* b, unsigned length) +{ + while (length--) { + unsigned char bc = *b++; + if (foldCase(*a++) != foldCase(bc)) + return false; + } + return true; +} + +static inline bool equalIgnoringCase(const UChar* a, const UChar* b, int length) +{ + ASSERT(length >= 0); + return umemcasecmp(a, b, length) == 0; +} + +int StringImpl::find(const char* chs, int index, bool caseSensitive) +{ + if (!chs || index < 0) + return -1; + + int chsLength = strlen(chs); + int n = m_length - index; + if (n < 0) + return -1; + n -= chsLength - 1; + if (n <= 0) + return -1; + + const char* chsPlusOne = chs + 1; + int chsLengthMinusOne = chsLength - 1; + + const UChar* ptr = m_data + index - 1; + if (caseSensitive) { + UChar c = *chs; + do { + if (*++ptr == c && equal(ptr + 1, chsPlusOne, chsLengthMinusOne)) + return m_length - chsLength - n + 1; + } while (--n); + } else { + UChar lc = Unicode::foldCase(*chs); + do { + if (Unicode::foldCase(*++ptr) == lc && equalIgnoringCase(ptr + 1, chsPlusOne, chsLengthMinusOne)) + return m_length - chsLength - n + 1; + } while (--n); + } + + return -1; +} + +int StringImpl::find(UChar c, int start) +{ + return WebCore::find(m_data, m_length, c, start); +} + +int StringImpl::find(CharacterMatchFunctionPtr matchFunction, int start) +{ + return WebCore::find(m_data, m_length, matchFunction, start); +} + +int StringImpl::find(StringImpl* str, int index, bool caseSensitive) +{ + /* + We use a simple trick for efficiency's sake. Instead of + comparing strings, we compare the sum of str with that of + a part of this string. Only if that matches, we call memcmp + or ucstrnicmp. + */ + ASSERT(str); + if (index < 0) + index += m_length; + int lstr = str->m_length; + int lthis = m_length - index; + if ((unsigned)lthis > m_length) + return -1; + int delta = lthis - lstr; + if (delta < 0) + return -1; + + const UChar* uthis = m_data + index; + const UChar* ustr = str->m_data; + unsigned hthis = 0; + unsigned hstr = 0; + if (caseSensitive) { + for (int i = 0; i < lstr; i++) { + hthis += uthis[i]; + hstr += ustr[i]; + } + int i = 0; + while (1) { + if (hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(UChar)) == 0) + return index + i; + if (i == delta) + return -1; + hthis += uthis[i + lstr]; + hthis -= uthis[i]; + i++; + } + } else { + for (int i = 0; i < lstr; i++ ) { + hthis += toASCIILower(uthis[i]); + hstr += toASCIILower(ustr[i]); + } + int i = 0; + while (1) { + if (hthis == hstr && equalIgnoringCase(uthis + i, ustr, lstr)) + return index + i; + if (i == delta) + return -1; + hthis += toASCIILower(uthis[i + lstr]); + hthis -= toASCIILower(uthis[i]); + i++; + } + } +} + +int StringImpl::reverseFind(UChar c, int index) +{ + return WebCore::reverseFind(m_data, m_length, c, index); +} + +int StringImpl::reverseFind(StringImpl* str, int index, bool caseSensitive) +{ + /* + See StringImpl::find() for explanations. + */ + ASSERT(str); + int lthis = m_length; + if (index < 0) + index += lthis; + + int lstr = str->m_length; + int delta = lthis - lstr; + if ( index < 0 || index > lthis || delta < 0 ) + return -1; + if ( index > delta ) + index = delta; + + const UChar *uthis = m_data; + const UChar *ustr = str->m_data; + unsigned hthis = 0; + unsigned hstr = 0; + int i; + if (caseSensitive) { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[index + i]; + hstr += ustr[i]; + } + i = index; + while (1) { + if (hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(UChar)) == 0) + return i; + if (i == 0) + return -1; + i--; + hthis -= uthis[i + lstr]; + hthis += uthis[i]; + } + } else { + for (i = 0; i < lstr; i++) { + hthis += toASCIILower(uthis[index + i]); + hstr += toASCIILower(ustr[i]); + } + i = index; + while (1) { + if (hthis == hstr && equalIgnoringCase(uthis + i, ustr, lstr) ) + return i; + if (i == 0) + return -1; + i--; + hthis -= toASCIILower(uthis[i + lstr]); + hthis += toASCIILower(uthis[i]); + } + } + + // Should never get here. + return -1; +} + +bool StringImpl::endsWith(StringImpl* m_data, bool caseSensitive) +{ + ASSERT(m_data); + int start = m_length - m_data->m_length; + if (start >= 0) + return (find(m_data, start, caseSensitive) == start); + return false; +} + +PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC) +{ + if (oldC == newC) + return this; + unsigned i; + for (i = 0; i != m_length; ++i) + if (m_data[i] == oldC) + break; + if (i == m_length) + return this; + + UChar* data; + PassRefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + for (i = 0; i != m_length; ++i) { + UChar ch = m_data[i]; + if (ch == oldC) + ch = newC; + data[i] = ch; + } + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToReplace, StringImpl* str) +{ + position = min(position, length()); + lengthToReplace = min(lengthToReplace, length() - position); + unsigned lengthToInsert = str ? str->length() : 0; + if (!lengthToReplace && !lengthToInsert) + return this; + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(length() - lengthToReplace + lengthToInsert, data); + memcpy(data, characters(), position * sizeof(UChar)); + if (str) + memcpy(data + position, str->characters(), lengthToInsert * sizeof(UChar)); + memcpy(data + position + lengthToInsert, characters() + position + lengthToReplace, + (length() - position - lengthToReplace) * sizeof(UChar)); + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacement) +{ + if (!replacement) + return this; + + int repStrLength = replacement->length(); + int srcSegmentStart = 0; + int matchCount = 0; + + // Count the matches + while ((srcSegmentStart = find(pattern, srcSegmentStart)) >= 0) { + ++matchCount; + ++srcSegmentStart; + } + + // If we have 0 matches, we don't have to do any more work + if (!matchCount) + return this; + + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(m_length - matchCount + (matchCount * repStrLength), data); + + // Construct the new data + int srcSegmentEnd; + int srcSegmentLength; + srcSegmentStart = 0; + int dstOffset = 0; + + while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) { + srcSegmentLength = srcSegmentEnd - srcSegmentStart; + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + dstOffset += srcSegmentLength; + memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); + dstOffset += repStrLength; + srcSegmentStart = srcSegmentEnd + 1; + } + + srcSegmentLength = m_length - srcSegmentStart; + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + + ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length())); + + return newImpl; +} + +PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement) +{ + if (!pattern || !replacement) + return this; + + int patternLength = pattern->length(); + if (!patternLength) + return this; + + int repStrLength = replacement->length(); + int srcSegmentStart = 0; + int matchCount = 0; + + // Count the matches + while ((srcSegmentStart = find(pattern, srcSegmentStart)) >= 0) { + ++matchCount; + srcSegmentStart += patternLength; + } + + // If we have 0 matches, we don't have to do any more work + if (!matchCount) + return this; + + UChar* data; + PassRefPtr<StringImpl> newImpl = + createUninitialized(m_length + matchCount * (repStrLength - patternLength), data); + + // Construct the new data + int srcSegmentEnd; + int srcSegmentLength; + srcSegmentStart = 0; + int dstOffset = 0; + + while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) { + srcSegmentLength = srcSegmentEnd - srcSegmentStart; + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + dstOffset += srcSegmentLength; + memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar)); + dstOffset += repStrLength; + srcSegmentStart = srcSegmentEnd + patternLength; + } + + srcSegmentLength = m_length - srcSegmentStart; + memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar)); + + ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length())); + + return newImpl; +} + +bool equal(const StringImpl* a, const StringImpl* b) +{ + return StringHash::equal(a, b); +} + +bool equal(const StringImpl* a, const char* b) +{ + if (!a) + return !b; + if (!b) + return !a; + + unsigned length = a->length(); + const UChar* as = a->characters(); + for (unsigned i = 0; i != length; ++i) { + unsigned char bc = b[i]; + if (!bc) + return false; + if (as[i] != bc) + return false; + } + + return !b[length]; +} + +bool equalIgnoringCase(StringImpl* a, StringImpl* b) +{ + return CaseFoldingHash::equal(a, b); +} + +bool equalIgnoringCase(StringImpl* a, const char* b) +{ + if (!a) + return !b; + if (!b) + return !a; + + unsigned length = a->length(); + const UChar* as = a->characters(); + + // Do a faster loop for the case where all the characters are ASCII. + UChar ored = 0; + bool equal = true; + for (unsigned i = 0; i != length; ++i) { + char bc = b[i]; + if (!bc) + return false; + UChar ac = as[i]; + ored |= ac; + equal = equal && (toASCIILower(ac) == toASCIILower(bc)); + } + + // Do a slower implementation for cases that include non-ASCII characters. + if (ored & ~0x7F) { + equal = true; + for (unsigned i = 0; i != length; ++i) { + unsigned char bc = b[i]; + equal = equal && (foldCase(as[i]) == foldCase(bc)); + } + } + + return equal && !b[length]; +} + +bool equalIgnoringNullity(StringImpl* a, StringImpl* b) +{ + if (StringHash::equal(a, b)) + return true; + if (!a && b && !b->length()) + return true; + if (!b && a && !a->length()) + return true; + + return false; +} + +Vector<char> StringImpl::ascii() +{ + Vector<char> buffer(m_length + 1); + for (unsigned i = 0; i != m_length; ++i) { + UChar c = m_data[i]; + if ((c >= 0x20 && c < 0x7F) || c == 0x00) + buffer[i] = static_cast<char>(c); + else + buffer[i] = '?'; + } + buffer[m_length] = '\0'; + return buffer; +} + +WTF::Unicode::Direction StringImpl::defaultWritingDirection() +{ + for (unsigned i = 0; i < m_length; ++i) { + WTF::Unicode::Direction charDirection = WTF::Unicode::direction(m_data[i]); + if (charDirection == WTF::Unicode::LeftToRight) + return WTF::Unicode::LeftToRight; + if (charDirection == WTF::Unicode::RightToLeft || charDirection == WTF::Unicode::RightToLeftArabic) + return WTF::Unicode::RightToLeft; + } + return WTF::Unicode::LeftToRight; +} + +// This is a hot function because it's used when parsing HTML. +PassRefPtr<StringImpl> StringImpl::createStrippingNullCharactersSlowCase(const UChar* characters, unsigned length) +{ + StringBuffer strippedCopy(length); + unsigned strippedLength = 0; + for (unsigned i = 0; i < length; i++) { + if (int c = characters[i]) + strippedCopy[strippedLength++] = c; + } + ASSERT(strippedLength < length); // Only take the slow case when stripping. + strippedCopy.shrink(strippedLength); + return adopt(strippedCopy); +} + +PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer& buffer) +{ + unsigned length = buffer.length(); + if (length == 0) + return empty(); + return adoptRef(new StringImpl(buffer.release(), length)); +} + +PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const StringImpl& string) +{ + // Use createUninitialized instead of 'new StringImpl' so that the string and its buffer + // get allocated in a single malloc block. + UChar* data; + int length = string.m_length; + RefPtr<StringImpl> terminatedString = createUninitialized(length + 1, data); + memcpy(data, string.m_data, length * sizeof(UChar)); + data[length] = 0; + terminatedString->m_length--; + terminatedString->m_hash = string.m_hash; + terminatedString->m_refCountAndFlags |= s_refCountFlagHasTerminatingNullCharacter; + return terminatedString.release(); +} + +PassRefPtr<StringImpl> StringImpl::threadsafeCopy() const +{ + return create(m_data, m_length); +} + +PassRefPtr<StringImpl> StringImpl::crossThreadString() +{ + if (SharedUChar* sharedBuffer = this->sharedBuffer()) + return adoptRef(new StringImpl(m_data, m_length, sharedBuffer->crossThreadCopy())); + + // If no shared buffer is available, create a copy. + return threadsafeCopy(); +} + +} // namespace WebCore diff --git a/JavaScriptCore/wtf/text/StringImpl.h b/JavaScriptCore/wtf/text/StringImpl.h new file mode 100644 index 0000000..dbf51e3 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringImpl.h @@ -0,0 +1,398 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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 StringImpl_h +#define StringImpl_h + +#include <limits.h> +#include <wtf/ASCIICType.h> +#include <wtf/CrossThreadRefCounted.h> +#include <wtf/OwnFastMallocPtr.h> +#include <wtf/StdLibExtras.h> +#include <wtf/StringHashFunctions.h> +#include <wtf/Vector.h> +#include <wtf/text/StringImplBase.h> +#include <wtf/unicode/Unicode.h> + +#if PLATFORM(CF) +typedef const struct __CFString * CFStringRef; +#endif + +#ifdef __OBJC__ +@class NSString; +#endif + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace JSC { + +struct IdentifierCStringTranslator; +struct IdentifierUCharBufferTranslator; + +} + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace WebCore { + +class StringBuffer; + +struct CStringTranslator; +struct HashAndCharactersTranslator; +struct StringHash; +struct UCharBufferTranslator; + +enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; + +typedef OwnFastMallocPtr<const UChar> SharableUChar; +typedef CrossThreadRefCounted<SharableUChar> SharedUChar; +typedef bool (*CharacterMatchFunctionPtr)(UChar); + +class StringImpl : public StringImplBase { + friend struct JSC::IdentifierCStringTranslator; + friend struct JSC::IdentifierUCharBufferTranslator; + friend struct CStringTranslator; + friend struct HashAndCharactersTranslator; + friend struct UCharBufferTranslator; + friend class AtomicStringImpl; +private: + // Used to construct static strings, which have an special refCount that can never hit zero. + // This means that the static string will never be destroyed, which is important because + // static strings will be shared across threads & ref-counted in a non-threadsafe manner. + StringImpl(const UChar* characters, unsigned length, StaticStringConstructType) + : StringImplBase(length, ConstructStaticString) + , m_data(characters) + , m_buffer(0) + , m_hash(0) + { + // Ensure that the hash is computed so that AtomicStringHash can call existingHash() + // with impunity. The empty string is special because it is never entered into + // AtomicString's HashKey, but still needs to compare correctly. + hash(); + } + + // Create a normal string with internal storage (BufferInternal) + StringImpl(unsigned length) + : StringImplBase(length, BufferInternal) + , m_data(reinterpret_cast<const UChar*>(this + 1)) + , m_buffer(0) + , m_hash(0) + { + ASSERT(m_data); + ASSERT(m_length); + } + + // Create a StringImpl adopting ownership of the provided buffer (BufferOwned) + StringImpl(const UChar* characters, unsigned length) + : StringImplBase(length, BufferOwned) + , m_data(characters) + , m_buffer(0) + , m_hash(0) + { + ASSERT(m_data); + ASSERT(m_length); + } + + // Used to create new strings that are a substring of an existing StringImpl (BufferSubstring) + StringImpl(const UChar* characters, unsigned length, PassRefPtr<StringImpl> base) + : StringImplBase(length, BufferSubstring) + , m_data(characters) + , m_substringBuffer(base.releaseRef()) + , m_hash(0) + { + ASSERT(m_data); + ASSERT(m_length); + ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring); + } + + // Used to construct new strings sharing an existing SharedUChar (BufferShared) + StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) + : StringImplBase(length, BufferShared) + , m_data(characters) + , m_sharedBuffer(sharedBuffer.releaseRef()) + , m_hash(0) + { + ASSERT(m_data); + ASSERT(m_length); + } + + // For use only by AtomicString's XXXTranslator helpers. + void setHash(unsigned hash) + { + ASSERT(!isStatic()); + ASSERT(!m_hash); + ASSERT(hash == computeHash(m_data, m_length)); + m_hash = hash; + } + +public: + ~StringImpl(); + + static PassRefPtr<StringImpl> create(const UChar*, unsigned length); + static PassRefPtr<StringImpl> create(const char*, unsigned length); + static PassRefPtr<StringImpl> create(const char*); + static PassRefPtr<StringImpl> create(const UChar*, unsigned length, PassRefPtr<SharedUChar> sharedBuffer); + static PassRefPtr<StringImpl> create(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length) + { + ASSERT(rep); + ASSERT(length <= rep->length()); + + if (!length) + return empty(); + + StringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get(); + return adoptRef(new StringImpl(rep->m_data + offset, length, ownerRep)); + } + + static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data); + static PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, UChar*& output) + { + if (!length) { + output = 0; + return empty(); + } + + if (length > ((std::numeric_limits<size_t>::max() - sizeof(StringImpl)) / sizeof(UChar))) + return 0; + StringImpl* resultImpl; + if (!tryFastMalloc(sizeof(UChar) * length + sizeof(StringImpl)).getValue(resultImpl)) + return 0; + output = reinterpret_cast<UChar*>(resultImpl + 1); + return adoptRef(new(resultImpl) StringImpl(length)); + } + + static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data); } + static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&); + static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length); + + template<size_t inlineCapacity> + static PassRefPtr<StringImpl> adopt(Vector<UChar, inlineCapacity>& vector) + { + if (size_t size = vector.size()) { + ASSERT(vector.data()); + return adoptRef(new StringImpl(vector.releaseBuffer(), size)); + } + return empty(); + } + static PassRefPtr<StringImpl> adopt(StringBuffer&); + + SharedUChar* sharedBuffer(); + const UChar* characters() const { return m_data; } + + size_t cost() + { + // For substrings, return the cost of the base string. + if (bufferOwnership() == BufferSubstring) + return m_substringBuffer->cost(); + + if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) { + m_refCountAndFlags &= ~s_refCountFlagShouldReportedCost; + return m_length; + } + return 0; + } + + bool isIdentifier() const { return m_refCountAndFlags & s_refCountFlagIsIdentifier; } + void setIsIdentifier(bool isIdentifier) + { + ASSERT(!isStatic()); + if (isIdentifier) + m_refCountAndFlags |= s_refCountFlagIsIdentifier; + else + m_refCountAndFlags &= ~s_refCountFlagIsIdentifier; + } + + bool hasTerminatingNullCharacter() const { return m_refCountAndFlags & s_refCountFlagHasTerminatingNullCharacter; } + + bool isAtomic() const { return m_refCountAndFlags & s_refCountFlagIsAtomic; } + void setIsAtomic(bool isIdentifier) + { + ASSERT(!isStatic()); + if (isIdentifier) + m_refCountAndFlags |= s_refCountFlagIsAtomic; + else + m_refCountAndFlags &= ~s_refCountFlagIsAtomic; + } + + unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } + unsigned existingHash() const { ASSERT(m_hash); return m_hash; } + static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } + static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); } + static unsigned computeHash(const char* data) { return WTF::stringHash(data); } + + ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } + ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic)) == s_refCountIncrement; } + + static StringImpl* empty(); + + static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) + { + if (numCharacters <= s_copyCharsInlineCutOff) { + for (unsigned i = 0; i < numCharacters; ++i) + destination[i] = source[i]; + } else + memcpy(destination, source, numCharacters * sizeof(UChar)); + } + + // Returns a StringImpl suitable for use on another thread. + PassRefPtr<StringImpl> crossThreadString(); + // Makes a deep copy. Helpful only if you need to use a String on another thread + // (use crossThreadString if the method call doesn't need to be threadsafe). + // Since StringImpl objects are immutable, there's no other reason to make a copy. + PassRefPtr<StringImpl> threadsafeCopy() const; + + PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); + + UChar operator[](unsigned i) { ASSERT(i < m_length); return m_data[i]; } + UChar32 characterStartingAt(unsigned); + + bool containsOnlyWhitespace(); + + int toIntStrict(bool* ok = 0, int base = 10); + unsigned toUIntStrict(bool* ok = 0, int base = 10); + int64_t toInt64Strict(bool* ok = 0, int base = 10); + uint64_t toUInt64Strict(bool* ok = 0, int base = 10); + intptr_t toIntPtrStrict(bool* ok = 0, int base = 10); + + int toInt(bool* ok = 0); // ignores trailing garbage + unsigned toUInt(bool* ok = 0); // ignores trailing garbage + int64_t toInt64(bool* ok = 0); // ignores trailing garbage + uint64_t toUInt64(bool* ok = 0); // ignores trailing garbage + intptr_t toIntPtr(bool* ok = 0); // ignores trailing garbage + + double toDouble(bool* ok = 0); + float toFloat(bool* ok = 0); + + PassRefPtr<StringImpl> lower(); + PassRefPtr<StringImpl> upper(); + PassRefPtr<StringImpl> secure(UChar aChar); + PassRefPtr<StringImpl> foldCase(); + + PassRefPtr<StringImpl> stripWhiteSpace(); + PassRefPtr<StringImpl> simplifyWhiteSpace(); + + PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr); + + int find(const char*, int index = 0, bool caseSensitive = true); + int find(UChar, int index = 0); + int find(CharacterMatchFunctionPtr, int index = 0); + int find(StringImpl*, int index, bool caseSensitive = true); + + int reverseFind(UChar, int index); + int reverseFind(StringImpl*, int index, bool caseSensitive = true); + + bool startsWith(StringImpl* str, bool caseSensitive = true) { return reverseFind(str, 0, caseSensitive) == 0; } + bool endsWith(StringImpl*, bool caseSensitive = true); + + PassRefPtr<StringImpl> replace(UChar, UChar); + PassRefPtr<StringImpl> replace(UChar, StringImpl*); + PassRefPtr<StringImpl> replace(StringImpl*, StringImpl*); + PassRefPtr<StringImpl> replace(unsigned index, unsigned len, StringImpl*); + + Vector<char> ascii(); + + WTF::Unicode::Direction defaultWritingDirection(); + +#if PLATFORM(CF) + CFStringRef createCFString(); +#endif +#ifdef __OBJC__ + operator NSString*(); +#endif + +private: + // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. + static const unsigned s_copyCharsInlineCutOff = 20; + + static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length); + + BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } + bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; } + const UChar* m_data; + union { + void* m_buffer; + StringImpl* m_substringBuffer; + SharedUChar* m_sharedBuffer; + }; + mutable unsigned m_hash; +}; + +bool equal(const StringImpl*, const StringImpl*); +bool equal(const StringImpl*, const char*); +inline bool equal(const char* a, StringImpl* b) { return equal(b, a); } + +bool equalIgnoringCase(StringImpl*, StringImpl*); +bool equalIgnoringCase(StringImpl*, const char*); +inline bool equalIgnoringCase(const char* a, StringImpl* b) { return equalIgnoringCase(b, a); } +bool equalIgnoringCase(const UChar* a, const char* b, unsigned length); +inline bool equalIgnoringCase(const char* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, a, length); } + +bool equalIgnoringNullity(StringImpl*, StringImpl*); + +static inline bool isSpaceOrNewline(UChar c) +{ + // Use isASCIISpace() for basic Latin-1. + // This will include newlines, which aren't included in Unicode DirWS. + return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF::Unicode::WhiteSpaceNeutral; +} + +// This is a hot function because it's used when parsing HTML. +inline PassRefPtr<StringImpl> StringImpl::createStrippingNullCharacters(const UChar* characters, unsigned length) +{ + ASSERT(characters); + ASSERT(length); + + // Optimize for the case where there are no Null characters by quickly + // searching for nulls, and then using StringImpl::create, which will + // memcpy the whole buffer. This is faster than assigning character by + // character during the loop. + + // Fast case. + int foundNull = 0; + for (unsigned i = 0; !foundNull && i < length; i++) { + int c = characters[i]; // more efficient than using UChar here (at least on Intel Mac OS) + foundNull |= !c; + } + if (!foundNull) + return StringImpl::create(characters, length); + + return StringImpl::createStrippingNullCharactersSlowCase(characters, length); +} + +} + +using WebCore::equal; + +namespace WTF { + + // WebCore::StringHash is the default hash for StringImpl* and RefPtr<StringImpl> + template<typename T> struct DefaultHash; + template<> struct DefaultHash<WebCore::StringImpl*> { + typedef WebCore::StringHash Hash; + }; + template<> struct DefaultHash<RefPtr<WebCore::StringImpl> > { + typedef WebCore::StringHash Hash; + }; + +} + +#endif diff --git a/JavaScriptCore/wtf/text/StringImplBase.h b/JavaScriptCore/wtf/text/StringImplBase.h new file mode 100644 index 0000000..6567672 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringImplBase.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StringImplBase_h +#define StringImplBase_h + +#include <wtf/Noncopyable.h> +#include <wtf/unicode/Unicode.h> + +namespace WTF { + +class StringImplBase : public Noncopyable { +public: + bool isStringImpl() { return (m_refCountAndFlags & s_refCountInvalidForStringImpl) != s_refCountInvalidForStringImpl; } + unsigned length() const { return m_length; } + void ref() { m_refCountAndFlags += s_refCountIncrement; } + +protected: + enum BufferOwnership { + BufferInternal, + BufferOwned, + BufferSubstring, + BufferShared, + }; + + using Noncopyable::operator new; + void* operator new(size_t, void* inPlace) { ASSERT(inPlace); return inPlace; } + + // For SmallStringStorage, which allocates an array and uses an in-place new. + StringImplBase() { } + + StringImplBase(unsigned length, BufferOwnership ownership) + : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership) + , m_length(length) + { + ASSERT(isStringImpl()); + } + + enum StaticStringConstructType { ConstructStaticString }; + StringImplBase(unsigned length, StaticStringConstructType) + : m_refCountAndFlags(s_refCountFlagStatic | s_refCountFlagIsIdentifier | BufferOwned) + , m_length(length) + { + ASSERT(isStringImpl()); + } + + // This constructor is not used when creating StringImpl objects, + // and sets the flags into a state marking the object as such. + enum NonStringImplConstructType { ConstructNonStringImpl }; + StringImplBase(NonStringImplConstructType) + : m_refCountAndFlags(s_refCountIncrement | s_refCountInvalidForStringImpl) + , m_length(0) + { + ASSERT(!isStringImpl()); + } + + // The bottom 7 bits hold flags, the top 25 bits hold the ref count. + // When dereferencing StringImpls we check for the ref count AND the + // static bit both being zero - static strings are never deleted. + static const unsigned s_refCountMask = 0xFFFFFF80; + static const unsigned s_refCountIncrement = 0x80; + static const unsigned s_refCountFlagStatic = 0x40; + static const unsigned s_refCountFlagHasTerminatingNullCharacter = 0x20; + static const unsigned s_refCountFlagIsAtomic = 0x10; + static const unsigned s_refCountFlagShouldReportedCost = 0x8; + static const unsigned s_refCountFlagIsIdentifier = 0x4; + static const unsigned s_refCountMaskBufferOwnership = 0x3; + // An invalid permutation of flags (static & shouldReportedCost - static strings do not + // set shouldReportedCost in the constructor, and this bit is only ever cleared, not set). + // Used by "ConstructNonStringImpl" constructor, above. + static const unsigned s_refCountInvalidForStringImpl = s_refCountFlagStatic | s_refCountFlagShouldReportedCost; + + unsigned m_refCountAndFlags; + unsigned m_length; +}; + +} // namespace WTF + +using WTF::StringImplBase; + +#endif diff --git a/JavaScriptCore/wtf/text/WTFString.cpp b/JavaScriptCore/wtf/text/WTFString.cpp new file mode 100644 index 0000000..a683e3d --- /dev/null +++ b/JavaScriptCore/wtf/text/WTFString.cpp @@ -0,0 +1,960 @@ +/* + * (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "WTFString.h" + +#include <limits> +#include <stdarg.h> +#include <wtf/ASCIICType.h> +#include <wtf/text/CString.h> +#include <wtf/StringExtras.h> +#include <wtf/Vector.h> +#include <wtf/dtoa.h> +#include <wtf/unicode/UTF8.h> +#include <wtf/unicode/Unicode.h> + +using namespace WTF; +using namespace WTF::Unicode; + +namespace WebCore { + +String::String(const UChar* str, unsigned len) +{ + if (!str) + return; + m_impl = StringImpl::create(str, len); +} + +String::String(const UChar* str) +{ + if (!str) + return; + + int len = 0; + while (str[len] != UChar(0)) + len++; + + m_impl = StringImpl::create(str, len); +} + +String::String(const char* str) +{ + if (!str) + return; + m_impl = StringImpl::create(str); +} + +String::String(const char* str, unsigned length) +{ + if (!str) + return; + m_impl = StringImpl::create(str, length); +} + +void String::append(const String& str) +{ + if (str.isEmpty()) + return; + + // FIXME: This is extremely inefficient. So much so that we might want to take this + // out of String's API. We can make it better by optimizing the case where exactly + // one String is pointing at this StringImpl, but even then it's going to require a + // call to fastMalloc every single time. + if (str.m_impl) { + if (m_impl) { + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + str.length(), data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + memcpy(data + m_impl->length(), str.characters(), str.length() * sizeof(UChar)); + m_impl = newImpl.release(); + } else + m_impl = str.m_impl; + } +} + +void String::append(char c) +{ + // FIXME: This is extremely inefficient. So much so that we might want to take this + // out of String's API. We can make it better by optimizing the case where exactly + // one String is pointing at this StringImpl, but even then it's going to require a + // call to fastMalloc every single time. + if (m_impl) { + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + 1, data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + data[m_impl->length()] = c; + m_impl = newImpl.release(); + } else + m_impl = StringImpl::create(&c, 1); +} + +void String::append(UChar c) +{ + // FIXME: This is extremely inefficient. So much so that we might want to take this + // out of String's API. We can make it better by optimizing the case where exactly + // one String is pointing at this StringImpl, but even then it's going to require a + // call to fastMalloc every single time. + if (m_impl) { + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(m_impl->length() + 1, data); + memcpy(data, m_impl->characters(), m_impl->length() * sizeof(UChar)); + data[m_impl->length()] = c; + m_impl = newImpl.release(); + } else + m_impl = StringImpl::create(&c, 1); +} + +String operator+(const String& a, const String& b) +{ + if (a.isEmpty()) + return b; + if (b.isEmpty()) + return a; + String c = a; + c += b; + return c; +} + +String operator+(const String& s, const char* cs) +{ + return s + String(cs); +} + +String operator+(const char* cs, const String& s) +{ + return String(cs) + s; +} + +void String::insert(const String& str, unsigned pos) +{ + if (str.isEmpty()) { + if (str.isNull()) + return; + if (isNull()) + m_impl = str.impl(); + return; + } + insert(str.characters(), str.length(), pos); +} + +void String::append(const UChar* charactersToAppend, unsigned lengthToAppend) +{ + if (!m_impl) { + if (!charactersToAppend) + return; + m_impl = StringImpl::create(charactersToAppend, lengthToAppend); + return; + } + + if (!lengthToAppend) + return; + + ASSERT(charactersToAppend); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() + lengthToAppend, data); + memcpy(data, characters(), length() * sizeof(UChar)); + memcpy(data + length(), charactersToAppend, lengthToAppend * sizeof(UChar)); + m_impl = newImpl.release(); +} + +void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, unsigned position) +{ + if (position >= length()) { + append(charactersToInsert, lengthToInsert); + return; + } + + ASSERT(m_impl); + + if (!lengthToInsert) + return; + + ASSERT(charactersToInsert); + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() + lengthToInsert, data); + memcpy(data, characters(), position * sizeof(UChar)); + memcpy(data + position, charactersToInsert, lengthToInsert * sizeof(UChar)); + memcpy(data + position + lengthToInsert, characters() + position, (length() - position) * sizeof(UChar)); + m_impl = newImpl.release(); +} + +UChar String::operator[](unsigned i) const +{ + if (!m_impl || i >= m_impl->length()) + return 0; + return m_impl->characters()[i]; +} + +UChar32 String::characterStartingAt(unsigned i) const +{ + if (!m_impl || i >= m_impl->length()) + return 0; + return m_impl->characterStartingAt(i); +} + +unsigned String::length() const +{ + if (!m_impl) + return 0; + return m_impl->length(); +} + +void String::truncate(unsigned position) +{ + if (position >= length()) + return; + UChar* data; + RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(position, data); + memcpy(data, characters(), position * sizeof(UChar)); + m_impl = newImpl.release(); +} + +void String::remove(unsigned position, int lengthToRemove) +{ + if (lengthToRemove <= 0) + return; + if (position >= length()) + return; + if (static_cast<unsigned>(lengthToRemove) > length() - position) + lengthToRemove = length() - position; + UChar* data; + RefPtr<StringImpl> newImpl = + StringImpl::createUninitialized(length() - lengthToRemove, data); + memcpy(data, characters(), position * sizeof(UChar)); + memcpy(data + position, characters() + position + lengthToRemove, + (length() - lengthToRemove - position) * sizeof(UChar)); + m_impl = newImpl.release(); +} + +String String::substring(unsigned pos, unsigned len) const +{ + if (!m_impl) + return String(); + return m_impl->substring(pos, len); +} + +String String::lower() const +{ + if (!m_impl) + return String(); + return m_impl->lower(); +} + +String String::upper() const +{ + if (!m_impl) + return String(); + return m_impl->upper(); +} + +String String::stripWhiteSpace() const +{ + if (!m_impl) + return String(); + return m_impl->stripWhiteSpace(); +} + +String String::simplifyWhiteSpace() const +{ + if (!m_impl) + return String(); + return m_impl->simplifyWhiteSpace(); +} + +String String::removeCharacters(CharacterMatchFunctionPtr findMatch) const +{ + if (!m_impl) + return String(); + return m_impl->removeCharacters(findMatch); +} + +String String::foldCase() const +{ + if (!m_impl) + return String(); + return m_impl->foldCase(); +} + +bool String::percentage(int& result) const +{ + if (!m_impl || !m_impl->length()) + return false; + + if ((*m_impl)[m_impl->length() - 1] != '%') + return false; + + result = charactersToIntStrict(m_impl->characters(), m_impl->length() - 1); + return true; +} + +const UChar* String::characters() const +{ + if (!m_impl) + return 0; + return m_impl->characters(); +} + +const UChar* String::charactersWithNullTermination() +{ + if (!m_impl) + return 0; + if (m_impl->hasTerminatingNullCharacter()) + return m_impl->characters(); + m_impl = StringImpl::createWithTerminatingNullCharacter(*m_impl); + return m_impl->characters(); +} + +String String::format(const char *format, ...) +{ +#if PLATFORM(QT) + // Use QString::vsprintf to avoid the locale dependent formatting of vsnprintf. + // https://bugs.webkit.org/show_bug.cgi?id=18994 + va_list args; + va_start(args, format); + + QString buffer; + buffer.vsprintf(format, args); + + va_end(args); + + return buffer; + +#elif OS(WINCE) + va_list args; + va_start(args, format); + + Vector<char, 256> buffer; + + int bufferSize = 256; + buffer.resize(bufferSize); + for (;;) { + int written = vsnprintf(buffer.data(), bufferSize, format, args); + va_end(args); + + if (written == 0) + return String(""); + if (written > 0) + return StringImpl::create(buffer.data(), written); + + bufferSize <<= 1; + buffer.resize(bufferSize); + va_start(args, format); + } + +#else + va_list args; + va_start(args, format); + + Vector<char, 256> buffer; + + // Do the format once to get the length. +#if COMPILER(MSVC) + int result = _vscprintf(format, args); +#else + char ch; + int result = vsnprintf(&ch, 1, format, args); + // We need to call va_end() and then va_start() again here, as the + // contents of args is undefined after the call to vsnprintf + // according to http://man.cx/snprintf(3) + // + // Not calling va_end/va_start here happens to work on lots of + // systems, but fails e.g. on 64bit Linux. + va_end(args); + va_start(args, format); +#endif + + if (result == 0) + return String(""); + if (result < 0) + return String(); + unsigned len = result; + buffer.grow(len + 1); + + // Now do the formatting again, guaranteed to fit. + vsnprintf(buffer.data(), buffer.size(), format, args); + + va_end(args); + + return StringImpl::create(buffer.data(), len); +#endif +} + +String String::number(short n) +{ + return String::format("%hd", n); +} + +String String::number(unsigned short n) +{ + return String::format("%hu", n); +} + +String String::number(int n) +{ + return String::format("%d", n); +} + +String String::number(unsigned n) +{ + return String::format("%u", n); +} + +String String::number(long n) +{ + return String::format("%ld", n); +} + +String String::number(unsigned long n) +{ + return String::format("%lu", n); +} + +String String::number(long long n) +{ +#if OS(WINDOWS) && !PLATFORM(QT) + return String::format("%I64i", n); +#else + return String::format("%lli", n); +#endif +} + +String String::number(unsigned long long n) +{ +#if OS(WINDOWS) && !PLATFORM(QT) + return String::format("%I64u", n); +#else + return String::format("%llu", n); +#endif +} + +String String::number(double n) +{ + return String::format("%.6lg", n); +} + +int String::toIntStrict(bool* ok, int base) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toIntStrict(ok, base); +} + +unsigned String::toUIntStrict(bool* ok, int base) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toUIntStrict(ok, base); +} + +int64_t String::toInt64Strict(bool* ok, int base) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toInt64Strict(ok, base); +} + +uint64_t String::toUInt64Strict(bool* ok, int base) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toUInt64Strict(ok, base); +} + +intptr_t String::toIntPtrStrict(bool* ok, int base) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toIntPtrStrict(ok, base); +} + + +int String::toInt(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toInt(ok); +} + +unsigned String::toUInt(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toUInt(ok); +} + +int64_t String::toInt64(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toInt64(ok); +} + +uint64_t String::toUInt64(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toUInt64(ok); +} + +intptr_t String::toIntPtr(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0; + } + return m_impl->toIntPtr(ok); +} + +double String::toDouble(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0.0; + } + return m_impl->toDouble(ok); +} + +float String::toFloat(bool* ok) const +{ + if (!m_impl) { + if (ok) + *ok = false; + return 0.0f; + } + return m_impl->toFloat(ok); +} + +String String::threadsafeCopy() const +{ + if (!m_impl) + return String(); + return m_impl->threadsafeCopy(); +} + +String String::crossThreadString() const +{ + if (!m_impl) + return String(); + return m_impl->crossThreadString(); +} + +bool String::isEmpty() const +{ + return !m_impl || !m_impl->length(); +} + +void String::split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const +{ + result.clear(); + + int startPos = 0; + int endPos; + while ((endPos = find(separator, startPos)) != -1) { + if (allowEmptyEntries || startPos != endPos) + result.append(substring(startPos, endPos - startPos)); + startPos = endPos + separator.length(); + } + if (allowEmptyEntries || startPos != static_cast<int>(length())) + result.append(substring(startPos)); +} + +void String::split(const String& separator, Vector<String>& result) const +{ + return split(separator, false, result); +} + +void String::split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const +{ + result.clear(); + + int startPos = 0; + int endPos; + while ((endPos = find(separator, startPos)) != -1) { + if (allowEmptyEntries || startPos != endPos) + result.append(substring(startPos, endPos - startPos)); + startPos = endPos + 1; + } + if (allowEmptyEntries || startPos != static_cast<int>(length())) + result.append(substring(startPos)); +} + +void String::split(UChar separator, Vector<String>& result) const +{ + return split(String(&separator, 1), false, result); +} + +Vector<char> String::ascii() const +{ + if (m_impl) + return m_impl->ascii(); + + const char* nullMsg = "(null impl)"; + Vector<char, 2048> buffer; + for (int i = 0; nullMsg[i]; ++i) + buffer.append(nullMsg[i]); + + buffer.append('\0'); + return buffer; +} + +CString String::latin1() const +{ + // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are + // preserved, characters outside of this range are converted to '?'. + + unsigned length = this->length(); + const UChar* characters = this->characters(); + + char* characterBuffer; + CString result = CString::newUninitialized(length, characterBuffer); + + for (unsigned i = 0; i < length; ++i) { + UChar ch = characters[i]; + characterBuffer[i] = ch > 255 ? '?' : ch; + } + + return result; +} + +// Helper to write a three-byte UTF-8 code point to the buffer, caller must check room is available. +static inline void putUTF8Triple(char*& buffer, UChar ch) +{ + ASSERT(ch >= 0x0800); + *buffer++ = static_cast<char>(((ch >> 12) & 0x0F) | 0xE0); + *buffer++ = static_cast<char>(((ch >> 6) & 0x3F) | 0x80); + *buffer++ = static_cast<char>((ch & 0x3F) | 0x80); +} + +CString String::utf8() const +{ + unsigned length = this->length(); + const UChar* characters = this->characters(); + + // Allocate a buffer big enough to hold all the characters + // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes). + // Optimization ideas, if we find this function is hot: + // * We could speculatively create a CStringBuffer to contain 'length' + // characters, and resize if necessary (i.e. if the buffer contains + // non-ascii characters). (Alternatively, scan the buffer first for + // ascii characters, so we know this will be sufficient). + // * We could allocate a CStringBuffer with an appropriate size to + // have a good chance of being able to write the string into the + // buffer without reallocing (say, 1.5 x length). + Vector<char, 1024> bufferVector(length * 3); + + char* buffer = bufferVector.data(); + ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), false); + ASSERT(result != sourceIllegal); // Only produced from strict conversion. + ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion + + // If a high surrogate is left unconverted, treat it the same was as an unpaired high surrogate + // would have been handled in the middle of a string with non-strict conversion - which is to say, + // simply encode it to UTF-8. + if (result == sourceExhausted) { + // This should be one unpaired high surrogate. + ASSERT((characters + 1) == (characters + length)); + ASSERT((*characters >= 0xD800) && (*characters <= 0xDBFF)); + // There should be room left, since one UChar hasn't been converted. + ASSERT((buffer + 3) <= (buffer + bufferVector.size())); + putUTF8Triple(buffer, *characters); + } + + return CString(bufferVector.data(), buffer - bufferVector.data()); +} + +String String::fromUTF8(const char* stringStart, size_t length) +{ + if (!stringStart) + return String(); + + // We'll use a StringImpl as a buffer; if the source string only contains ascii this should be + // the right length, if there are any multi-byte sequences this buffer will be too large. + UChar* buffer; + String stringBuffer(StringImpl::createUninitialized(length, buffer)); + UChar* bufferEnd = buffer + length; + + // Try converting into the buffer. + const char* stringCurrent = stringStart; + if (convertUTF8ToUTF16(&stringCurrent, stringStart + length, &buffer, bufferEnd) != conversionOK) + return String(); + + // stringBuffer is full (the input must have been all ascii) so just return it! + if (buffer == bufferEnd) + return stringBuffer; + + // stringBuffer served its purpose as a buffer, copy the contents out into a new string. + unsigned utf16Length = buffer - stringBuffer.characters(); + ASSERT(utf16Length < length); + return String(stringBuffer.characters(), utf16Length); +} + +String String::fromUTF8(const char* string) +{ + if (!string) + return String(); + return fromUTF8(string, strlen(string)); +} + +String String::fromUTF8WithLatin1Fallback(const char* string, size_t size) +{ + String utf8 = fromUTF8(string, size); + if (!utf8) + return String(string, size); + return utf8; +} + +// String Operations + +static bool isCharacterAllowedInBase(UChar c, int base) +{ + if (c > 0x7F) + return false; + if (isASCIIDigit(c)) + return c - '0' < base; + if (isASCIIAlpha(c)) { + if (base > 36) + base = 36; + return (c >= 'a' && c < 'a' + base - 10) + || (c >= 'A' && c < 'A' + base - 10); + } + return false; +} + +template <typename IntegralType> +static inline IntegralType toIntegralType(const UChar* data, size_t length, bool* ok, int base) +{ + static const IntegralType integralMax = std::numeric_limits<IntegralType>::max(); + static const bool isSigned = std::numeric_limits<IntegralType>::is_signed; + const IntegralType maxMultiplier = integralMax / base; + + IntegralType value = 0; + bool isOk = false; + bool isNegative = false; + + if (!data) + goto bye; + + // skip leading whitespace + while (length && isSpaceOrNewline(*data)) { + length--; + data++; + } + + if (isSigned && length && *data == '-') { + length--; + data++; + isNegative = true; + } else if (length && *data == '+') { + length--; + data++; + } + + if (!length || !isCharacterAllowedInBase(*data, base)) + goto bye; + + while (length && isCharacterAllowedInBase(*data, base)) { + length--; + IntegralType digitValue; + UChar c = *data; + if (isASCIIDigit(c)) + digitValue = c - '0'; + else if (c >= 'a') + digitValue = c - 'a' + 10; + else + digitValue = c - 'A' + 10; + + if (value > maxMultiplier || (value == maxMultiplier && digitValue > (integralMax % base) + isNegative)) + goto bye; + + value = base * value + digitValue; + data++; + } + +#if COMPILER(MSVC) +#pragma warning(push, 0) +#pragma warning(disable:4146) +#endif + + if (isNegative) + value = -value; + +#if COMPILER(MSVC) +#pragma warning(pop) +#endif + + // skip trailing space + while (length && isSpaceOrNewline(*data)) { + length--; + data++; + } + + if (!length) + isOk = true; +bye: + if (ok) + *ok = isOk; + return isOk ? value : 0; +} + +static unsigned lengthOfCharactersAsInteger(const UChar* data, size_t length) +{ + size_t i = 0; + + // Allow leading spaces. + for (; i != length; ++i) { + if (!isSpaceOrNewline(data[i])) + break; + } + + // Allow sign. + if (i != length && (data[i] == '+' || data[i] == '-')) + ++i; + + // Allow digits. + for (; i != length; ++i) { + if (!isASCIIDigit(data[i])) + break; + } + + return i; +} + +int charactersToIntStrict(const UChar* data, size_t length, bool* ok, int base) +{ + return toIntegralType<int>(data, length, ok, base); +} + +unsigned charactersToUIntStrict(const UChar* data, size_t length, bool* ok, int base) +{ + return toIntegralType<unsigned>(data, length, ok, base); +} + +int64_t charactersToInt64Strict(const UChar* data, size_t length, bool* ok, int base) +{ + return toIntegralType<int64_t>(data, length, ok, base); +} + +uint64_t charactersToUInt64Strict(const UChar* data, size_t length, bool* ok, int base) +{ + return toIntegralType<uint64_t>(data, length, ok, base); +} + +intptr_t charactersToIntPtrStrict(const UChar* data, size_t length, bool* ok, int base) +{ + return toIntegralType<intptr_t>(data, length, ok, base); +} + +int charactersToInt(const UChar* data, size_t length, bool* ok) +{ + return toIntegralType<int>(data, lengthOfCharactersAsInteger(data, length), ok, 10); +} + +unsigned charactersToUInt(const UChar* data, size_t length, bool* ok) +{ + return toIntegralType<unsigned>(data, lengthOfCharactersAsInteger(data, length), ok, 10); +} + +int64_t charactersToInt64(const UChar* data, size_t length, bool* ok) +{ + return toIntegralType<int64_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10); +} + +uint64_t charactersToUInt64(const UChar* data, size_t length, bool* ok) +{ + return toIntegralType<uint64_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10); +} + +intptr_t charactersToIntPtr(const UChar* data, size_t length, bool* ok) +{ + return toIntegralType<intptr_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10); +} + +double charactersToDouble(const UChar* data, size_t length, bool* ok) +{ + if (!length) { + if (ok) + *ok = false; + return 0.0; + } + + Vector<char, 256> bytes(length + 1); + for (unsigned i = 0; i < length; ++i) + bytes[i] = data[i] < 0x7F ? data[i] : '?'; + bytes[length] = '\0'; + char* end; + double val = WTF::strtod(bytes.data(), &end); + if (ok) + *ok = (end == 0 || *end == '\0'); + return val; +} + +float charactersToFloat(const UChar* data, size_t length, bool* ok) +{ + // FIXME: This will return ok even when the string fits into a double but not a float. + return static_cast<float>(charactersToDouble(data, length, ok)); +} + +} // namespace WebCore + +#ifndef NDEBUG +// For use in the debugger - leaks memory +WebCore::String* string(const char*); + +WebCore::String* string(const char* s) +{ + return new WebCore::String(s); +} +#endif diff --git a/JavaScriptCore/wtf/text/WTFString.h b/JavaScriptCore/wtf/text/WTFString.h new file mode 100644 index 0000000..7c3c2dd --- /dev/null +++ b/JavaScriptCore/wtf/text/WTFString.h @@ -0,0 +1,398 @@ +/* + * (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple 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 WTFString_h +#define WTFString_h + +// This file would be called String.h, but that conflicts with <string.h> +// on systems without case-sensitive file systems. + +#include "StringImpl.h" + +#ifdef __OBJC__ +#include <objc/objc.h> +#endif + +#if PLATFORM(CF) +typedef const struct __CFString * CFStringRef; +#endif + +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE +#include <QDataStream> +#endif + +#if PLATFORM(WX) +class wxString; +#endif + +#if PLATFORM(HAIKU) +class BString; +#endif + +namespace WTF { +class CString; +} +using WTF::CString; + +// FIXME: This is a temporary layering violation while we move string code to WTF. +// Landing the file moves in one patch, will follow on with patches to change the namespaces. +namespace WebCore { + +class SharedBuffer; +struct StringHash; + +// Declarations of string operations + +bool charactersAreAllASCII(const UChar*, size_t); +int charactersToIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10); +unsigned charactersToUIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10); +int64_t charactersToInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10); +uint64_t charactersToUInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10); +intptr_t charactersToIntPtrStrict(const UChar*, size_t, bool* ok = 0, int base = 10); + +int charactersToInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage +unsigned charactersToUInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage +int64_t charactersToInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage +uint64_t charactersToUInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage +intptr_t charactersToIntPtr(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage + +double charactersToDouble(const UChar*, size_t, bool* ok = 0); +float charactersToFloat(const UChar*, size_t, bool* ok = 0); + +int find(const UChar*, size_t, UChar, int startPosition = 0); +int reverseFind(const UChar*, size_t, UChar, int startPosition = -1); + +class String { +public: + String() { } // gives null string, distinguishable from an empty string + String(const UChar*, unsigned length); + String(const UChar*); // Specifically for null terminated UTF-16 + String(const char*); + String(const char*, unsigned length); + String(StringImpl* i) : m_impl(i) { } + String(PassRefPtr<StringImpl> i) : m_impl(i) { } + String(RefPtr<StringImpl> i) : m_impl(i) { } + + void swap(String& o) { m_impl.swap(o.m_impl); } + + // Hash table deleted values, which are only constructed and never copied or destroyed. + String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } + bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } + + static String adopt(StringBuffer& buffer) { return StringImpl::adopt(buffer); } + static String adopt(Vector<UChar>& vector) { return StringImpl::adopt(vector); } + + unsigned length() const; + const UChar* characters() const; + const UChar* charactersWithNullTermination(); + + UChar operator[](unsigned i) const; // if i >= length(), returns 0 + UChar32 characterStartingAt(unsigned) const; // Ditto. + + bool contains(UChar c) const { return find(c) != -1; } + bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != -1; } + bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != -1; } + + int find(UChar c, int start = 0) const + { return m_impl ? m_impl->find(c, start) : -1; } + int find(CharacterMatchFunctionPtr matchFunction, int start = 0) const + { return m_impl ? m_impl->find(matchFunction, start) : -1; } + int find(const char* str, int start = 0, bool caseSensitive = true) const + { return m_impl ? m_impl->find(str, start, caseSensitive) : -1; } + int find(const String& str, int start = 0, bool caseSensitive = true) const + { return m_impl ? m_impl->find(str.impl(), start, caseSensitive) : -1; } + + int reverseFind(UChar c, int start = -1) const + { return m_impl ? m_impl->reverseFind(c, start) : -1; } + int reverseFind(const String& str, int start = -1, bool caseSensitive = true) const + { return m_impl ? m_impl->reverseFind(str.impl(), start, caseSensitive) : -1; } + + bool startsWith(const String& s, bool caseSensitive = true) const + { return m_impl ? m_impl->startsWith(s.impl(), caseSensitive) : s.isEmpty(); } + bool endsWith(const String& s, bool caseSensitive = true) const + { return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); } + + void append(const String&); + void append(char); + void append(UChar); + void append(const UChar*, unsigned length); + void insert(const String&, unsigned pos); + void insert(const UChar*, unsigned length, unsigned pos); + + String& replace(UChar a, UChar b) { if (m_impl) m_impl = m_impl->replace(a, b); return *this; } + String& replace(UChar a, const String& b) { if (m_impl) m_impl = m_impl->replace(a, b.impl()); return *this; } + String& replace(const String& a, const String& b) { if (m_impl) m_impl = m_impl->replace(a.impl(), b.impl()); return *this; } + String& replace(unsigned index, unsigned len, const String& b) { if (m_impl) m_impl = m_impl->replace(index, len, b.impl()); return *this; } + + void makeLower() { if (m_impl) m_impl = m_impl->lower(); } + void makeUpper() { if (m_impl) m_impl = m_impl->upper(); } + void makeSecure(UChar aChar) { if (m_impl) m_impl = m_impl->secure(aChar); } + + void truncate(unsigned len); + void remove(unsigned pos, int len = 1); + + String substring(unsigned pos, unsigned len = UINT_MAX) const; + String left(unsigned len) const { return substring(0, len); } + String right(unsigned len) const { return substring(length() - len, len); } + + // Returns a lowercase/uppercase version of the string + String lower() const; + String upper() const; + + String stripWhiteSpace() const; + String simplifyWhiteSpace() const; + + String removeCharacters(CharacterMatchFunctionPtr) const; + + // Return the string with case folded for case insensitive comparison. + String foldCase() const; + + static String number(short); + static String number(unsigned short); + static String number(int); + static String number(unsigned); + static String number(long); + static String number(unsigned long); + static String number(long long); + static String number(unsigned long long); + static String number(double); + + static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2); + + // Returns an uninitialized string. The characters needs to be written + // into the buffer returned in data before the returned string is used. + // Failure to do this will have unpredictable results. + static String createUninitialized(unsigned length, UChar*& data) { return StringImpl::createUninitialized(length, data); } + + void split(const String& separator, Vector<String>& result) const; + void split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const; + void split(UChar separator, Vector<String>& result) const; + void split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const; + + int toIntStrict(bool* ok = 0, int base = 10) const; + unsigned toUIntStrict(bool* ok = 0, int base = 10) const; + int64_t toInt64Strict(bool* ok = 0, int base = 10) const; + uint64_t toUInt64Strict(bool* ok = 0, int base = 10) const; + intptr_t toIntPtrStrict(bool* ok = 0, int base = 10) const; + + int toInt(bool* ok = 0) const; + unsigned toUInt(bool* ok = 0) const; + int64_t toInt64(bool* ok = 0) const; + uint64_t toUInt64(bool* ok = 0) const; + intptr_t toIntPtr(bool* ok = 0) const; + double toDouble(bool* ok = 0) const; + float toFloat(bool* ok = 0) const; + + bool percentage(int& percentage) const; + + // Returns a StringImpl suitable for use on another thread. + String crossThreadString() const; + // Makes a deep copy. Helpful only if you need to use a String on another thread + // (use crossThreadString if the method call doesn't need to be threadsafe). + // Since the underlying StringImpl objects are immutable, there's no other reason + // to ever prefer copy() over plain old assignment. + String threadsafeCopy() const; + + bool isNull() const { return !m_impl; } + bool isEmpty() const; + + StringImpl* impl() const { return m_impl.get(); } + +#if PLATFORM(CF) + String(CFStringRef); + CFStringRef createCFString() const; +#endif + +#ifdef __OBJC__ + String(NSString*); + + // This conversion maps NULL to "", which loses the meaning of NULL, but we + // need this mapping because AppKit crashes when passed nil NSStrings. + operator NSString*() const { if (!m_impl) return @""; return *m_impl; } +#endif + +#if PLATFORM(QT) + String(const QString&); + String(const QStringRef&); + operator QString() const; +#endif + +#if PLATFORM(WX) + String(const wxString&); + operator wxString() const; +#endif + +#if PLATFORM(HAIKU) + String(const BString&); + operator BString() const; +#endif + + Vector<char> ascii() const; + + CString latin1() const; + CString utf8() const; + + static String fromUTF8(const char*, size_t); + static String fromUTF8(const char*); + + // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8. + static String fromUTF8WithLatin1Fallback(const char*, size_t); + + // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3. + WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; } + + bool containsOnlyASCII() const { return charactersAreAllASCII(characters(), length()); } + +private: + RefPtr<StringImpl> m_impl; +}; + +#if PLATFORM(QT) +QDataStream& operator<<(QDataStream& stream, const String& str); +QDataStream& operator>>(QDataStream& stream, String& str); +#endif + +String operator+(const String&, const String&); +String operator+(const String&, const char*); +String operator+(const char*, const String&); + +inline String& operator+=(String& a, const String& b) { a.append(b); return a; } + +inline bool operator==(const String& a, const String& b) { return equal(a.impl(), b.impl()); } +inline bool operator==(const String& a, const char* b) { return equal(a.impl(), b); } +inline bool operator==(const char* a, const String& b) { return equal(a, b.impl()); } + +inline bool operator!=(const String& a, const String& b) { return !equal(a.impl(), b.impl()); } +inline bool operator!=(const String& a, const char* b) { return !equal(a.impl(), b); } +inline bool operator!=(const char* a, const String& b) { return !equal(a, b.impl()); } + +inline bool equalIgnoringCase(const String& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); } +inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), b); } +inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(a, b.impl()); } + +inline bool equalPossiblyIgnoringCase(const String& a, const String& b, bool ignoreCase) +{ + return ignoreCase ? equalIgnoringCase(a, b) : (a == b); +} + +inline bool equalIgnoringNullity(const String& a, const String& b) { return equalIgnoringNullity(a.impl(), b.impl()); } + +inline bool operator!(const String& str) { return str.isNull(); } + +inline void swap(String& a, String& b) { a.swap(b); } + +// Definitions of string operations + +#ifdef __OBJC__ +// This is for situations in WebKit where the long standing behavior has been +// "nil if empty", so we try to maintain longstanding behavior for the sake of +// entrenched clients +inline NSString* nsStringNilIfEmpty(const String& str) { return str.isEmpty() ? nil : (NSString*)str; } +#endif + +inline bool charactersAreAllASCII(const UChar* characters, size_t length) +{ + UChar ored = 0; + for (size_t i = 0; i < length; ++i) + ored |= characters[i]; + return !(ored & 0xFF80); +} + +inline int find(const UChar* characters, size_t length, UChar character, int startPosition) +{ + if (startPosition >= static_cast<int>(length)) + return -1; + for (size_t i = startPosition; i < length; ++i) { + if (characters[i] == character) + return static_cast<int>(i); + } + return -1; +} + +inline int find(const UChar* characters, size_t length, CharacterMatchFunctionPtr matchFunction, int startPosition) +{ + if (startPosition >= static_cast<int>(length)) + return -1; + for (size_t i = startPosition; i < length; ++i) { + if (matchFunction(characters[i])) + return static_cast<int>(i); + } + return -1; +} + +inline int reverseFind(const UChar* characters, size_t length, UChar character, int startPosition) +{ + if (startPosition >= static_cast<int>(length) || !length) + return -1; + if (startPosition < 0) + startPosition += static_cast<int>(length); + while (true) { + if (characters[startPosition] == character) + return startPosition; + if (!startPosition) + return -1; + startPosition--; + } + ASSERT_NOT_REACHED(); + return -1; +} + +inline void append(Vector<UChar>& vector, const String& string) +{ + vector.append(string.characters(), string.length()); +} + +inline void appendNumber(Vector<UChar>& vector, unsigned char number) +{ + int numberLength = number > 99 ? 3 : (number > 9 ? 2 : 1); + size_t vectorSize = vector.size(); + vector.grow(vectorSize + numberLength); + + switch (numberLength) { + case 3: + vector[vectorSize + 2] = number % 10 + '0'; + number /= 10; + + case 2: + vector[vectorSize + 1] = number % 10 + '0'; + number /= 10; + + case 1: + vector[vectorSize] = number % 10 + '0'; + } +} + +} // namespace WebCore + +namespace WTF { + + // StringHash is the default hash for String + template<typename T> struct DefaultHash; + template<> struct DefaultHash<WebCore::String> { + typedef WebCore::StringHash Hash; + }; + +} + +#endif diff --git a/JavaScriptCore/wtf/unicode/Collator.h b/JavaScriptCore/wtf/unicode/Collator.h index 51e8a06..fe6a809 100644 --- a/JavaScriptCore/wtf/unicode/Collator.h +++ b/JavaScriptCore/wtf/unicode/Collator.h @@ -29,8 +29,8 @@ #ifndef WTF_Collator_h #define WTF_Collator_h -#include <memory> #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #include <wtf/unicode/Unicode.h> #if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION @@ -47,7 +47,7 @@ namespace WTF { ~Collator(); void setOrderLowerFirst(bool); - static std::auto_ptr<Collator> userDefault(); + static PassOwnPtr<Collator> userDefault(); Result collate(const ::UChar*, size_t, const ::UChar*, size_t) const; diff --git a/JavaScriptCore/wtf/unicode/CollatorDefault.cpp b/JavaScriptCore/wtf/unicode/CollatorDefault.cpp index eddbe53..4e05432 100644 --- a/JavaScriptCore/wtf/unicode/CollatorDefault.cpp +++ b/JavaScriptCore/wtf/unicode/CollatorDefault.cpp @@ -45,9 +45,9 @@ void Collator::setOrderLowerFirst(bool) { } -std::auto_ptr<Collator> Collator::userDefault() +PassOwnPtr<Collator> Collator::userDefault() { - return std::auto_ptr<Collator>(new Collator(0)); + return new Collator(0); } // A default implementation for platforms that lack Unicode-aware collation. diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h index d72e707..46b00ea 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h +++ b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h @@ -26,7 +26,7 @@ #define UnicodeGLib_h #include "UnicodeMacrosFromICU.h" -#include <wtf/gtk/GOwnPtr.h> +#include "GOwnPtr.h" #include <glib.h> #include <pango/pango.h> diff --git a/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp index a1753a4..ecab5bd 100644 --- a/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp +++ b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp @@ -57,7 +57,7 @@ Collator::Collator(const char* locale) { } -std::auto_ptr<Collator> Collator::userDefault() +PassOwnPtr<Collator> Collator::userDefault() { #if OS(DARWIN) && PLATFORM(CF) // Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work. @@ -71,11 +71,11 @@ std::auto_ptr<Collator> Collator::userDefault() char buf[256]; if (collationOrder) { CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII); - return std::auto_ptr<Collator>(new Collator(buf)); + return new Collator(buf); } else - return std::auto_ptr<Collator>(new Collator("")); + return new Collator(""); #else - return std::auto_ptr<Collator>(new Collator(0)); + return new Collator(0); #endif } diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index 9b1754a..97c42b7 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -56,7 +56,7 @@ namespace QUnicodeTables { QT_END_NAMESPACE // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h -#if defined(Q_OS_WIN) || COMPILER(WINSCW) || COMPILER(RVCT) +#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && OS(SYMBIAN)) typedef wchar_t UChar; #else typedef uint16_t UChar; diff --git a/JavaScriptCore/wtf/url/src/URLComponent.h b/JavaScriptCore/wtf/url/src/URLComponent.h new file mode 100644 index 0000000..ca7e6f3 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLComponent.h @@ -0,0 +1,71 @@ +// Copyright 2010, 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 URLComponent_h +#define URLComponent_h + +namespace WTF { + +// Represents a substring for URL parsing. +class URLComponent { +public: + URLComponent() : m_begin(0), m_length(-1) { } + URLComponent(int begin, int length) : m_begin(begin), m_length(length) { } + + // Returns true if this component is valid, meaning the length is given. Even + // valid components may be empty to record the fact that they exist. + bool isValid() const { return m_length != -1; } + + // Returns true if the given component is specified on false, the component + // is either empty or invalid. + bool isNonempty() const { return m_length > 0; } + + void reset() + { + m_begin = 0; + m_length = -1; + } + + bool operator==(const URLComponent& other) const { return m_begin == other.m_begin && m_length == other.m_length; } + + int begin() const { return m_begin; } + void setBegin(int begin) { m_begin = begin; } + + int length() const { return m_length; } + void setLength(int length) { m_length = length; } + + int end() const { return m_begin + m_length; } + +private: + int m_begin; // Byte offset in the string of this component. + int m_length; // Will be -1 if the component is unspecified. +}; + +} // namespace WTF + +#endif // URLComponent_h diff --git a/JavaScriptCore/wtf/url/src/URLSegments.cpp b/JavaScriptCore/wtf/url/src/URLSegments.cpp new file mode 100644 index 0000000..bb9542f --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLSegments.cpp @@ -0,0 +1,110 @@ +/* Based on nsURLParsers.cc from Mozilla + * ------------------------------------- + * Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Darin Fisher (original author) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "URLSegments.h" + +namespace WTF { + +int URLSegments::length() const +{ + if (fragment.isValid()) + return fragment.end(); + return charactersBefore(Fragment, false); +} + +int URLSegments::charactersBefore(ComponentType type, bool includeDelimiter) const +{ + if (type == Scheme) + return scheme.begin(); + + int current = 0; + if (scheme.isValid()) + current = scheme.end() + 1; // Advance over the ':' at the end of the scheme. + + if (username.isValid()) { + if (type <= Username) + return username.begin(); + current = username.end() + 1; // Advance over the '@' or ':' at the end. + } + + if (password.isValid()) { + if (type <= Password) + return password.begin(); + current = password.end() + 1; // Advance over the '@' at the end. + } + + if (host.isValid()) { + if (type <= Host) + return host.begin(); + current = host.end(); + } + + if (port.isValid()) { + if (type < Port || (type == Port && includeDelimiter)) + return port.begin() - 1; // Back over delimiter. + if (type == Port) + return port.begin(); // Don't want delimiter counted. + current = port.end(); + } + + if (path.isValid()) { + if (type <= Path) + return path.begin(); + current = path.end(); + } + + if (query.isValid()) { + if (type < Query || (type == Query && includeDelimiter)) + return query.begin() - 1; // Back over delimiter. + if (type == Query) + return query.begin(); // Don't want delimiter counted. + current = query.end(); + } + + if (fragment.isValid()) { + if (type == Fragment && !includeDelimiter) + return fragment.begin(); // Back over delimiter. + + // When there is a fragment and we get here, the component we wanted was before + // this and not found, so we always know the beginning of the fragment is right. + return fragment.begin() - 1; // Don't want delimiter counted. + } + + return current; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/url/src/URLSegments.h b/JavaScriptCore/wtf/url/src/URLSegments.h new file mode 100644 index 0000000..436c7fe --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLSegments.h @@ -0,0 +1,105 @@ +// Copyright 2007, 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 URLSegments_h +#define URLSegments_h + +#include "URLComponent.h" + +namespace WTF { + +// A structure that holds the identified parts of an input URL. This structure +// does NOT store the URL itself. The caller will have to store the URL text +// and its corresponding Parsed structure separately. +class URLSegments { +public: + // Identifies different components. + enum ComponentType { + Scheme, + Username, + Password, + Host, + Port, + Path, + Query, + Fragment, + }; + + URLSegments() { } + + // Returns the length of the URL (the end of the last component). + // + // Note that for some invalid, non-canonical URLs, this may not be the length + // of the string. For example "http://": the parsed structure will only + // contain an entry for the four-character scheme, and it doesn't know about + // the "://". For all other last-components, it will return the real length. + int length() const; + + // Returns the number of characters before the given component if it exists, + // or where the component would be if it did exist. This will return the + // string length if the component would be appended to the end. + // + // Note that this can get a little funny for the port, query, and fragment + // components which have a delimiter that is not counted as part of the + // component. The |includeDelimiter| flag controls if you want this counted + // as part of the component or not when the component exists. + // + // This example shows the difference between the two flags for two of these + // delimited components that is present (the port and query) and one that + // isn't (the reference). The components that this flag affects are marked + // with a *. + // 0 1 2 + // 012345678901234567890 + // Example input: http://foo:80/?query + // include_delim=true, ...=false ("<-" indicates different) + // Scheme: 0 0 + // Username: 5 5 + // Password: 5 5 + // Host: 7 7 + // *Port: 10 11 <- + // Path: 13 13 + // *Query: 14 15 <- + // *Fragment: 20 20 + // + int charactersBefore(ComponentType, bool includeDelimiter) const; + + // Each component excludes the related delimiters and has a length of -1 + // if that component is absent but 0 if the component exists but is empty. + URLComponent scheme; + URLComponent username; + URLComponent password; + URLComponent host; + URLComponent port; + URLComponent path; + URLComponent query; + URLComponent fragment; +}; + +} // namespace WTF + +#endif // URLSegments_h diff --git a/JavaScriptCore/wtf/url/wtfurl.gyp b/JavaScriptCore/wtf/url/wtfurl.gyp new file mode 100644 index 0000000..f254ae4 --- /dev/null +++ b/JavaScriptCore/wtf/url/wtfurl.gyp @@ -0,0 +1,58 @@ +# 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'wtfurl', + 'type': '<(library)', + 'msvs_guid': 'EF5E94AB-B646-4E5B-A058-52EF07B8351C', + 'dependencies': [ + ], + 'sources': [ + 'src/URLComponent.h', + 'src/URLSegments.cpp', + 'src/URLSegments.h', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src', + ], + }, + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/JavaScriptCore/wtf/win/MainThreadWin.cpp b/JavaScriptCore/wtf/win/MainThreadWin.cpp index ee70b59..ee3a273 100644 --- a/JavaScriptCore/wtf/win/MainThreadWin.cpp +++ b/JavaScriptCore/wtf/win/MainThreadWin.cpp @@ -77,6 +77,8 @@ void initializeMainThreadPlatform() threadingWindowHandle = CreateWindow(kThreadingWindowClassName, 0, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWndParent, 0, 0, 0); threadingFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.MainThreadFired"); + + initializeCurrentThreadInternal("Main Thread"); } void scheduleDispatchFunctionsOnMainThread() diff --git a/JavaScriptCore/wtf/OwnPtrWin.cpp b/JavaScriptCore/wtf/win/OwnPtrWin.cpp index 67a32ff..67a32ff 100644 --- a/JavaScriptCore/wtf/OwnPtrWin.cpp +++ b/JavaScriptCore/wtf/win/OwnPtrWin.cpp diff --git a/JavaScriptCore/wtf/wx/MainThreadWx.cpp b/JavaScriptCore/wtf/wx/MainThreadWx.cpp index bcd5f05..e1d15c9 100644 --- a/JavaScriptCore/wtf/wx/MainThreadWx.cpp +++ b/JavaScriptCore/wtf/wx/MainThreadWx.cpp @@ -29,6 +29,29 @@ #include "config.h" #include "MainThread.h" +#include <wx/defs.h> +#include <wx/app.h> +#include <wx/event.h> + +const wxEventType wxEVT_CALL_AFTER = wxNewEventType(); + +class wxCallAfter : public wxEvtHandler +{ +public: + wxCallAfter() + : wxEvtHandler() + { + wxTheApp->Connect(-1, -1, wxEVT_CALL_AFTER, wxCommandEventHandler(wxCallAfter::OnCallback)); + wxCommandEvent event(wxEVT_CALL_AFTER); + wxPostEvent(wxTheApp, event); + } + + void OnCallback(wxCommandEvent& event) + { + WTF::dispatchFunctionsFromMainThread(); + } +}; + namespace WTF { void initializeMainThreadPlatform() @@ -37,6 +60,7 @@ void initializeMainThreadPlatform() void scheduleDispatchFunctionsOnMainThread() { + wxCallAfter(); } } // namespace WTF |