diff options
Diffstat (limited to 'JavaScriptCore/wtf')
159 files changed, 14296 insertions, 3241 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/AVLTree.h b/JavaScriptCore/wtf/AVLTree.h index d7470e7..ec8a639 100644 --- a/JavaScriptCore/wtf/AVLTree.h +++ b/JavaScriptCore/wtf/AVLTree.h @@ -33,6 +33,7 @@ #define AVL_TREE_H_ #include "Assertions.h" +#include <wtf/FixedArray.h> namespace WTF { @@ -70,7 +71,7 @@ public: void reset() { for (unsigned i = 0; i < maxDepth; ++i) m_data[i] = false; } private: - bool m_data[maxDepth]; + FixedArray<bool, maxDepth> m_data; }; // How to determine maxDepth: 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.cpp b/JavaScriptCore/wtf/Assertions.cpp index cadbc91..1841150 100644 --- a/JavaScriptCore/wtf/Assertions.cpp +++ b/JavaScriptCore/wtf/Assertions.cpp @@ -35,23 +35,54 @@ #include <CoreFoundation/CFString.h> #endif -#if COMPILER(MSVC) && !OS(WINCE) +#if COMPILER(MSVC) && !OS(WINCE) && !PLATFORM(BREWMP) #ifndef WINVER #define WINVER 0x0500 #endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif -#include <windows.h> #include <crtdbg.h> #endif -#if OS(WINCE) -#include <winbase.h> +#if OS(WINDOWS) +#include <windows.h> +#endif + +#if PLATFORM(BREWMP) +#include <AEEdbg.h> +#include <wtf/Vector.h> #endif extern "C" { +#if PLATFORM(BREWMP) + +static void printLog(const Vector<char>& buffer) +{ + // Each call to DBGPRINTF generates at most 128 bytes of output on the Windows SDK. + // On Qualcomm chipset targets, DBGPRINTF() comes out the diag port (though this may change). + // The length of each output string is constrained even more than on the Windows SDK. +#if COMPILER(MSVC) + const int printBufferSize = 128; +#else + const int printBufferSize = 32; +#endif + + char printBuffer[printBufferSize + 1]; + printBuffer[printBufferSize] = 0; // to guarantee null termination + + const char* p = buffer.data(); + const char* end = buffer.data() + buffer.size(); + while (p < end) { + strncpy(printBuffer, p, printBufferSize); + dbg_Message(printBuffer, DBG_MSG_LEVEL_HIGH, __FILE__, __LINE__); + p += printBufferSize; + } +} + +#endif + WTF_ATTRIBUTE_PRINTF(1, 0) static void vprintf_stderr_common(const char* format, va_list args) { @@ -71,7 +102,17 @@ static void vprintf_stderr_common(const char* format, va_list args) CFRelease(str); CFRelease(cfFormat); } else -#elif COMPILER(MSVC) && !defined(WINCEBASIC) +#elif PLATFORM(BREWMP) + // When str is 0, the return value is the number of bytes needed + // to accept the result including null termination. + int size = vsnprintf(0, 0, format, args); + if (size > 0) { + Vector<char> buffer(size); + vsnprintf(buffer.data(), size, format, args); + printLog(buffer); + } + +#elif HAVE(ISDEBUGGERPRESENT) if (IsDebuggerPresent()) { size_t size = 1024; diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index 0e02af5..3f3af72 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -44,9 +44,9 @@ #include "Platform.h" -#if COMPILER(MSVC) #include <stddef.h> -#else + +#if !COMPILER(MSVC) #include <inttypes.h> #endif @@ -55,13 +55,19 @@ #include <e32debug.h> #endif +#if PLATFORM(BREWMP) +#include <AEEError.h> +#include <AEEdbg.h> +#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,14 +154,26 @@ 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 { \ __DEBUGGER(); \ User::Panic(_L("Webkit CRASH"),0); \ } while(false) +#elif PLATFORM(BREWMP) +#define CRASH() do { \ + dbg_Message("WebKit CRASH", DBG_MSG_LEVEL_FATAL, __FILE__, __LINE__); \ + *(int *)(uintptr_t)0xbbadbeef = 0; \ + ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ +} while(false) #else #define CRASH() do { \ *(int *)(uintptr_t)0xbbadbeef = 0; \ @@ -164,7 +182,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. */ @@ -191,7 +213,14 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann #define ASSERT(assertion) ((void)0) #define ASSERT_NOT_REACHED() ((void)0) + +#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +template<typename T> +inline void assertUnused(T& x) { (void)x; } +#define ASSERT_UNUSED(variable, assertion) (assertUnused(variable)) +#else #define ASSERT_UNUSED(variable, assertion) ((void)variable) +#endif #else @@ -213,7 +242,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 +282,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 +297,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 +309,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 +323,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/Bitmap.h b/JavaScriptCore/wtf/Bitmap.h new file mode 100644 index 0000000..4dd88f6 --- /dev/null +++ b/JavaScriptCore/wtf/Bitmap.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2010 Apple 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. + * + * 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 + * + */ +#ifndef Bitmap_h +#define Bitmap_h + +#include "FixedArray.h" +#include "StdLibExtras.h" + +#include <stdint.h> + +namespace WTF { + +template<size_t size> +class Bitmap { +private: + typedef uint32_t WordType; + +public: + Bitmap(); + + bool get(size_t) const; + void set(size_t); + void clear(size_t); + void clearAll(); + void advanceToNextFreeBit(size_t&) const; + size_t count(size_t = 0) const; + size_t isEmpty() const; + size_t isFull() const; + +private: + static const WordType wordSize = sizeof(WordType) * 8; + static const WordType words = (size + wordSize - 1) / wordSize; + + // the literal '1' is of type signed int. We want to use an unsigned + // version of the correct size when doing the calculations because if + // WordType is larger than int, '1 << 31' will first be sign extended + // and then casted to unsigned, meaning that set(31) when WordType is + // a 64 bit unsigned int would give 0xffff8000 + static const WordType one = 1; + + FixedArray<WordType, words> bits; +}; + +template<size_t size> +inline Bitmap<size>::Bitmap() +{ + clearAll(); +} + +template<size_t size> +inline bool Bitmap<size>::get(size_t n) const +{ + return !!(bits[n / wordSize] & (one << (n % wordSize))); +} + +template<size_t size> +inline void Bitmap<size>::set(size_t n) +{ + bits[n / wordSize] |= (one << (n % wordSize)); +} + +template<size_t size> +inline void Bitmap<size>::clear(size_t n) +{ + bits[n / wordSize] &= ~(one << (n % wordSize)); +} + +template<size_t size> +inline void Bitmap<size>::clearAll() +{ + memset(bits.data(), 0, sizeof(bits)); +} + +template<size_t size> +inline void Bitmap<size>::advanceToNextFreeBit(size_t& start) const +{ + if (!~bits[start / wordSize]) + start = ((start / wordSize) + 1) * wordSize; + else + ++start; +} + +template<size_t size> +inline size_t Bitmap<size>::count(size_t start) const +{ + size_t result = 0; + for ( ; (start % wordSize); ++start) { + if (get(start)) + ++result; + } + for (size_t i = start / wordSize; i < words; ++i) + result += WTF::bitCount(bits[i]); + return result; +} + +template<size_t size> +inline size_t Bitmap<size>::isEmpty() const +{ + for (size_t i = 0; i < words; ++i) + if (bits[i]) + return false; + return true; +} + +template<size_t size> +inline size_t Bitmap<size>::isFull() const +{ + for (size_t i = 0; i < words; ++i) + if (~bits[i]) + return false; + return true; +} + +} +#endif diff --git a/JavaScriptCore/wtf/BumpPointerAllocator.h b/JavaScriptCore/wtf/BumpPointerAllocator.h new file mode 100644 index 0000000..3deefe6 --- /dev/null +++ b/JavaScriptCore/wtf/BumpPointerAllocator.h @@ -0,0 +1,253 @@ +/* + * 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 BumpPointerAllocator_h +#define BumpPointerAllocator_h + +#include <wtf/PageAllocation.h> + +namespace WTF { + +#define MINIMUM_BUMP_POOL_SIZE 0x1000 + +class BumpPointerPool { +public: + // ensureCapacity will check whether the current pool has capacity to + // allocate 'size' bytes of memory If it does not, it will attempt to + // allocate a new pool (which will be added to this one in a chain). + // + // If allocation fails (out of memory) this method will return null. + // If the return value is non-null, then callers should update any + // references they have to this current (possibly full) BumpPointerPool + // to instead point to the newly returned BumpPointerPool. + BumpPointerPool* ensureCapacity(size_t size) + { + void* allocationEnd = static_cast<char*>(m_current) + size; + ASSERT(allocationEnd > m_current); // check for overflow + if (allocationEnd <= static_cast<void*>(this)) + return this; + return ensureCapacityCrossPool(this, size); + } + + // alloc should only be called after calling ensureCapacity; as such + // alloc will never fail. + void* alloc(size_t size) + { + void* current = m_current; + void* allocationEnd = static_cast<char*>(current) + size; + ASSERT(allocationEnd > current); // check for overflow + ASSERT(allocationEnd <= static_cast<void*>(this)); + m_current = allocationEnd; + return current; + } + + // The dealloc method releases memory allocated using alloc. Memory + // must be released in a LIFO fashion, e.g. if the client calls alloc + // four times, returning pointer A, B, C, D, then the only valid order + // in which these may be deallocaed is D, C, B, A. + // + // The client may optionally skip some deallocations. In the example + // above, it would be valid to only explicitly dealloc C, A (D being + // dealloced along with C, B along with A). + // + // If pointer was not allocated from this pool (or pools) then dealloc + // will CRASH(). Callers should update any references they have to + // this current BumpPointerPool to instead point to the returned + // BumpPointerPool. + BumpPointerPool* dealloc(void* position) + { + if ((position >= m_start) && (position <= static_cast<void*>(this))) { + ASSERT(position <= m_current); + m_current = position; + return this; + } + return deallocCrossPool(this, position); + } + +private: + // Placement operator new, returns the last 'size' bytes of allocation for use as this. + void* operator new(size_t size, const PageAllocation& allocation) + { + ASSERT(size < allocation.size()); + return reinterpret_cast<char*>(reinterpret_cast<intptr_t>(allocation.base()) + allocation.size()) - size; + } + + BumpPointerPool(const PageAllocation& allocation) + : m_current(allocation.base()) + , m_start(allocation.base()) + , m_next(0) + , m_previous(0) + , m_allocation(allocation) + { + } + + static BumpPointerPool* create(size_t minimumCapacity = 0) + { + // Add size of BumpPointerPool object, check for overflow. + minimumCapacity += sizeof(BumpPointerPool); + if (minimumCapacity < sizeof(BumpPointerPool)) + return 0; + + size_t poolSize = MINIMUM_BUMP_POOL_SIZE; + while (poolSize < minimumCapacity) { + poolSize <<= 1; + // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2! + ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1))); + if (!poolSize) + return 0; + } + + PageAllocation allocation = PageAllocation::allocate(poolSize); + if (!!allocation) + return new(allocation) BumpPointerPool(allocation); + return 0; + } + + void shrink() + { + ASSERT(!m_previous); + m_current = m_start; + while (m_next) { + BumpPointerPool* nextNext = m_next->m_next; + m_next->destroy(); + m_next = nextNext; + } + } + + void destroy() + { + // Don't call deallocate on allocation, because allocation is *inside* allocation, + // and it will get deallocated before deallocate has completed! + PageAllocation allocation = m_allocation; + allocation.deallocate(); + } + + static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size) + { + // The pool passed should not have capacity, so we'll start with the next one. + ASSERT(previousPool); + ASSERT((static_cast<char*>(previousPool->m_current) + size) > previousPool->m_current); // check for overflow + ASSERT((static_cast<char*>(previousPool->m_current) + size) > static_cast<void*>(previousPool)); + BumpPointerPool* pool = previousPool->m_next; + + while (true) { + if (!pool) { + // We've run to the end; allocate a new pool. + pool = BumpPointerPool::create(size); + previousPool->m_next = pool; + pool->m_previous = previousPool; + return pool; + } + + // + void* current = pool->m_current; + void* allocationEnd = static_cast<char*>(current) + size; + ASSERT(allocationEnd > current); // check for overflow + if (allocationEnd <= static_cast<void*>(pool)) + return pool; + } + } + + static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position) + { + // Should only be called if position is not in the current pool. + ASSERT((position < pool->m_start) || (position > static_cast<void*>(pool))); + + while (true) { + // Unwind the current pool to the start, move back in the chain to the previous pool. + pool->m_current = pool->m_start; + pool = pool->m_previous; + + // position was nowhere in the chain! + if (!pool) + CRASH(); + + if ((position >= pool->m_start) && (position <= static_cast<void*>(pool))) { + ASSERT(position <= pool->m_current); + pool->m_current = position; + return pool; + } + } + } + + void* m_current; + void* m_start; + BumpPointerPool* m_next; + BumpPointerPool* m_previous; + PageAllocation m_allocation; + + friend class BumpPointerAllocator; +}; + +// A BumpPointerAllocator manages a set of BumpPointerPool objects, which +// can be used for LIFO (stack like) allocation. +// +// To begin allocating using this class call startAllocator(). The result +// of this method will be null if the initial pool allocation fails, or a +// pointer to a BumpPointerPool object that can be used to perform +// allocations. Whilst running no memory will be released until +// stopAllocator() is called. At this point all allocations made through +// this allocator will be reaped, and underlying memory may be freed. +// +// (In practice we will still hold on to the initial pool to allow allocation +// to be quickly restared, but aditional pools will be freed). +// +// This allocator is non-renetrant, it is encumbant on the clients to ensure +// startAllocator() is not called again until stopAllocator() has been called. +class BumpPointerAllocator { +public: + BumpPointerAllocator() + : m_head(0) + { + } + + ~BumpPointerAllocator() + { + if (m_head) + m_head->destroy(); + } + + BumpPointerPool* startAllocator() + { + if (!m_head) + m_head = BumpPointerPool::create(); + return m_head; + } + + void stopAllocator() + { + if (m_head) + m_head->shrink(); + } + +private: + BumpPointerPool* m_head; +}; + +} + +using WTF::BumpPointerAllocator; + +#endif // BumpPointerAllocator_h diff --git a/JavaScriptCore/wtf/ByteArray.cpp b/JavaScriptCore/wtf/ByteArray.cpp index 526f147..910af59 100644 --- a/JavaScriptCore/wtf/ByteArray.cpp +++ b/JavaScriptCore/wtf/ByteArray.cpp @@ -25,12 +25,13 @@ #include "config.h" #include "ByteArray.h" +#include "StdLibExtras.h" namespace WTF { PassRefPtr<ByteArray> ByteArray::create(size_t size) { - unsigned char* buffer = new unsigned char[size + sizeof(ByteArray) - sizeof(size_t)]; + unsigned char* buffer = new unsigned char[size + OBJECT_OFFSETOF(ByteArray, m_data)]; ASSERT((reinterpret_cast<size_t>(buffer) & 3) == 0); return adoptRef(new (buffer) ByteArray(size)); } diff --git a/JavaScriptCore/wtf/ByteArray.h b/JavaScriptCore/wtf/ByteArray.h index f5f5ded..bdec630 100644 --- a/JavaScriptCore/wtf/ByteArray.h +++ b/JavaScriptCore/wtf/ByteArray.h @@ -26,7 +26,9 @@ #ifndef ByteArray_h #define ByteArray_h +#include <limits.h> #include <wtf/PassRefPtr.h> +#include <wtf/Platform.h> #include <wtf/RefCounted.h> namespace WTF { @@ -86,8 +88,17 @@ namespace WTF { { } size_t m_size; - unsigned char m_data[sizeof(size_t)]; +// MSVC can't handle correctly unsized array. +// warning C4200: nonstandard extension used : zero-sized array in struct/union +// Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array +#if COMPILER(MSVC) + unsigned char m_data[INT_MAX]; +#else + unsigned char m_data[]; +#endif }; -} +} // namespace WTF + +using WTF::ByteArray; #endif diff --git a/JavaScriptCore/wtf/CMakeLists.txt b/JavaScriptCore/wtf/CMakeLists.txt new file mode 100644 index 0000000..898d19b --- /dev/null +++ b/JavaScriptCore/wtf/CMakeLists.txt @@ -0,0 +1,51 @@ +SET(WTF_SOURCES + Assertions.cpp + ByteArray.cpp + CurrentTime.cpp + DecimalNumber.cpp + FastMalloc.cpp + HashTable.cpp + MainThread.cpp + MD5.cpp + RandomNumber.cpp + RefCountedLeakCounter.cpp + StringExtras.cpp + Threading.cpp + TypeTraits.cpp + WTFThreadData.cpp + dtoa.cpp + + text/AtomicString.cpp + text/CString.cpp + text/StringBuilder.cpp + text/StringImpl.cpp + text/StringStatics.cpp + text/WTFString.cpp + + unicode/UTF8.cpp +) + +SET(WTF_LIBRARIES +) + +SET(WTF_PORT_FLAGS ) +INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/wtf/CMakeLists${PORT}.txt) + +LIST(APPEND WTF_INCLUDE_DIRECTORIES + "${CMAKE_BINARY_DIR}" +) + +WEBKIT_WRAP_SOURCELIST(${WTF_SOURCES}) +INCLUDE_DIRECTORIES(${WTF_INCLUDE_DIRECTORIES}) +ADD_DEFINITIONS(-DBUILDING_WTF) +ADD_LIBRARY(${WTF_LIBRARY_NAME} ${WTF_LIBRARY_TYPE} ${WTF_SOURCES}) +TARGET_LINK_LIBRARIES(${WTF_LIBRARY_NAME} ${WTF_LIBRARIES}) + +IF (WTF_LINK_FLAGS) + ADD_TARGET_PROPERTIES(${WTF_LIBRARY_NAME} LINK_FLAGS "${WTF_LINK_FLAGS}") +ENDIF () + +IF (SHARED_CORE) + SET_TARGET_PROPERTIES(${WTF_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) + INSTALL(TARGETS ${WTF_LIBRARY_NAME} DESTINATION lib) +ENDIF () diff --git a/JavaScriptCore/wtf/CMakeListsEfl.txt b/JavaScriptCore/wtf/CMakeListsEfl.txt new file mode 100644 index 0000000..e5d8bd7 --- /dev/null +++ b/JavaScriptCore/wtf/CMakeListsEfl.txt @@ -0,0 +1,46 @@ +IF (ENABLE_FAST_MALLOC) + LIST(APPEND WTF_SOURCES + TCSystemAlloc.cpp + ) +ELSE () + ADD_DEFINITIONS(-DUSE_SYSTEM_MALLOC=1) +ENDIF() + +LIST(APPEND WTF_SOURCES + efl/MainThreadEfl.cpp + + ThreadIdentifierDataPthreads.cpp + ThreadingPthreads.cpp + + unicode/icu/CollatorICU.cpp +) + +IF (ENABLE_GLIB_SUPPORT) + LIST(APPEND WTF_SOURCES + gobject/GOwnPtr.cpp + gobject/GRefPtr.cpp + ) + + LIST(APPEND WTF_INCLUDE_DIRECTORIES + ${Glib_INCLUDE_DIRS} + ${JAVASCRIPTCORE_DIR}/wtf/gobject + ) + + LIST(APPEND WTF_LIBRARIES + ${Glib_LIBRARIES} + ) +ENDIF () + +LIST(APPEND WTF_LIBRARIES + pthread + ${ICU_LIBRARIES} +) + +LIST(APPEND WTF_LINK_FLAGS + ${ECORE_LDFLAGS} +) + +LIST(APPEND WTF_INCLUDE_DIRECTORIES + ${ECORE_INCLUDE_DIRS} + ${JAVASCRIPTCORE_DIR}/wtf/unicode/ +) diff --git a/JavaScriptCore/wtf/Complex.h b/JavaScriptCore/wtf/Complex.h index cfd1d20..7da8511 100644 --- a/JavaScriptCore/wtf/Complex.h +++ b/JavaScriptCore/wtf/Complex.h @@ -26,13 +26,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Complex_h -#define Complex_h +#ifndef WTF_Complex_h +#define WTF_Complex_h #include <complex> #include <wtf/MathExtras.h> -namespace WebCore { +namespace WTF { typedef std::complex<double> Complex; @@ -41,6 +41,6 @@ inline Complex complexFromMagnitudePhase(double magnitude, double phase) return Complex(magnitude * cos(phase), magnitude * sin(phase)); } -} // namespace WebCore +} // namespace WTF -#endif // Complex_h +#endif // WTF_Complex_h diff --git a/JavaScriptCore/wtf/CrossThreadRefCounted.h b/JavaScriptCore/wtf/CrossThreadRefCounted.h index f682f0d..0c0e997 100644 --- a/JavaScriptCore/wtf/CrossThreadRefCounted.h +++ b/JavaScriptCore/wtf/CrossThreadRefCounted.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Google Inc. All rights reserved. + * 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 @@ -31,10 +32,9 @@ #ifndef CrossThreadRefCounted_h #define CrossThreadRefCounted_h -#include <wtf/Noncopyable.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/Threading.h> +#include "PassRefPtr.h" +#include "RefCounted.h" +#include "Threading.h" namespace WTF { @@ -78,6 +78,9 @@ namespace WTF { , m_threadId(0) #endif { + // We use RefCountedBase in an unusual way here, so get rid of the requirement + // that adoptRef be called on it. + m_refCounter.relaxAdoptionRequirement(); } ~CrossThreadRefCounted() diff --git a/JavaScriptCore/wtf/CurrentTime.cpp b/JavaScriptCore/wtf/CurrentTime.cpp index 30ca7c3..56724cb 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 @@ -165,7 +163,6 @@ double currentTime() // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. - static bool started; static double syncLowResUTCTime; static double syncHighResUpTime; static double lastUTCTime; @@ -251,13 +248,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 +283,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..7119656 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); @@ -61,6 +61,7 @@ namespace WTF { } // namespace WTF using WTF::currentTime; +using WTF::currentTimeMS; using WTF::getLocalTime; #endif // CurrentTime_h diff --git a/JavaScriptCore/wtf/DateMath.cpp b/JavaScriptCore/wtf/DateMath.cpp index b9a0207..f3627e6 100644 --- a/JavaScriptCore/wtf/DateMath.cpp +++ b/JavaScriptCore/wtf/DateMath.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) 2010 &yet, LLC. (nate@andyet.net) * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. @@ -75,6 +76,7 @@ #include "ASCIICType.h" #include "CurrentTime.h" #include "MathExtras.h" +#include "StdLibExtras.h" #include "StringExtras.h" #include <algorithm> @@ -479,7 +481,7 @@ void initializeDates() equivalentYearForDST(2000); // Need to call once to initialize a static used in this function. } -static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second) +static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, double second) { double days = (day - 32075) + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4) @@ -557,6 +559,162 @@ static bool parseLong(const char* string, char** stopPosition, int base, long* r return true; } +double parseES5DateFromNullTerminatedCharacters(const char* dateString) +{ + // This parses a date of the form defined in ECMA-262-5, section 15.9.1.15 + // (similar to RFC 3339 / ISO 8601: YYYY-MM-DDTHH:mm:ss[.sss]Z). + // In most cases it is intentionally strict (e.g. correct field widths, no stray whitespace). + + static const long daysPerMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + const char* currentPosition = dateString; + char* postParsePosition; + + // This is a bit more lenient on the year string than ES5 specifies: + // instead of restricting to 4 digits (or 6 digits with mandatory +/-), + // it accepts any integer value. Consider this an implementation fallback. + long year; + if (!parseLong(currentPosition, &postParsePosition, 10, &year)) + return NaN; + if (*postParsePosition != '-') + return NaN; + currentPosition = postParsePosition + 1; + + long month; + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &month)) + return NaN; + if (*postParsePosition != '-' || (postParsePosition - currentPosition) != 2) + return NaN; + currentPosition = postParsePosition + 1; + + long day; + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &day)) + return NaN; + if (*postParsePosition != 'T' || (postParsePosition - currentPosition) != 2) + return NaN; + currentPosition = postParsePosition + 1; + + long hours; + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &hours)) + return NaN; + if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) + return NaN; + currentPosition = postParsePosition + 1; + + long minutes; + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &minutes)) + return NaN; + if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) + return NaN; + currentPosition = postParsePosition + 1; + + long intSeconds; + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds)) + return NaN; + if ((postParsePosition - currentPosition) != 2) + return NaN; + + double seconds = intSeconds; + if (*postParsePosition == '.') { + currentPosition = postParsePosition + 1; + + // In ECMA-262-5 it's a bit unclear if '.' can be present without milliseconds, but + // a reasonable interpretation guided by the given examples and RFC 3339 says "no". + // We check the next character to avoid reading +/- timezone hours after an invalid decimal. + if (!isASCIIDigit(*currentPosition)) + return NaN; + + // We are more lenient than ES5 by accepting more or less than 3 fraction digits. + long fracSeconds; + if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds)) + return NaN; + + long numFracDigits = postParsePosition - currentPosition; + seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigits)); + } + currentPosition = postParsePosition; + + // A few of these checks could be done inline above, but since many of them are interrelated + // we would be sacrificing readability to "optimize" the (presumably less common) failure path. + if (month < 1 || month > 12) + return NaN; + if (day < 1 || day > daysPerMonth[month - 1]) + return NaN; + if (month == 2 && day > 28 && !isLeapYear(year)) + return NaN; + if (hours < 0 || hours > 24) + return NaN; + if (hours == 24 && (minutes || seconds)) + return NaN; + if (minutes < 0 || minutes > 59) + return NaN; + if (seconds < 0 || seconds >= 61) + return NaN; + if (seconds > 60) { + // Discard leap seconds by clamping to the end of a minute. + seconds = 60; + } + + long timeZoneSeconds = 0; + if (*currentPosition != 'Z') { + bool tzNegative; + if (*currentPosition == '-') + tzNegative = true; + else if (*currentPosition == '+') + tzNegative = false; + else + return NaN; + currentPosition += 1; + + long tzHours; + long tzHoursAbs; + long tzMinutes; + + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours)) + return NaN; + if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) + return NaN; + tzHoursAbs = abs(tzHours); + currentPosition = postParsePosition + 1; + + if (!isASCIIDigit(*currentPosition)) + return NaN; + if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes)) + return NaN; + if ((postParsePosition - currentPosition) != 2) + return NaN; + currentPosition = postParsePosition; + + if (tzHoursAbs > 24) + return NaN; + if (tzMinutes < 0 || tzMinutes > 59) + return NaN; + + timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs)); + if (tzNegative) + timeZoneSeconds = -timeZoneSeconds; + } else { + currentPosition += 1; + } + if (*currentPosition) + return NaN; + + double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, seconds) - timeZoneSeconds; + return dateSeconds * msPerSecond; +} + // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore. static double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset) { @@ -793,7 +951,7 @@ static double parseDateFromNullTerminatedCharacters(const char* dateString, bool } haveTZ = true; } else { - for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) { + for (size_t i = 0; i < WTF_ARRAY_LENGTH(known_zones); ++i) { if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { offset = known_zones[i].tzOffset; dateString += strlen(known_zones[i].tzName); diff --git a/JavaScriptCore/wtf/DateMath.h b/JavaScriptCore/wtf/DateMath.h index 033d25e..be51947 100644 --- a/JavaScriptCore/wtf/DateMath.h +++ b/JavaScriptCore/wtf/DateMath.h @@ -53,7 +53,8 @@ namespace WTF { void initializeDates(); int equivalentYearForDST(int year); -// Not really math related, but this is currently the only shared place to put these. +// Not really math related, but this is currently the only shared place to put these. +double parseES5DateFromNullTerminatedCharacters(const char* dateString); double parseDateFromNullTerminatedCharacters(const char* dateString); double timeClip(double); @@ -94,6 +95,7 @@ using WTF::msPerDay; using WTF::msPerSecond; using WTF::msToYear; using WTF::secondsPerMinute; +using WTF::parseDateFromNullTerminatedCharacters; #if USE(JSC) namespace JSC { diff --git a/JavaScriptCore/wtf/DecimalNumber.cpp b/JavaScriptCore/wtf/DecimalNumber.cpp new file mode 100644 index 0000000..70304e2 --- /dev/null +++ b/JavaScriptCore/wtf/DecimalNumber.cpp @@ -0,0 +1,199 @@ +/* + * 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. + */ + +#include "config.h" +#include "DecimalNumber.h" +#include <math.h> +#include <wtf/MathExtras.h> +#include <wtf/text/WTFString.h> + +namespace WTF { + +unsigned DecimalNumber::bufferLengthForStringDecimal() const +{ + unsigned length = 0; + // if the exponent is negative the number decimal representation is of the form: + // [<sign>]0.[<zeros>]<significand> + if (m_exponent < 0) { + if (m_sign) + ++length; + length += 2; // for "0." + length += -m_exponent - 1; + length += m_precision; + return length; + } + + unsigned digitsBeforeDecimalPoint = m_exponent + 1; + + // If the precision is <= than the number of digits to get up to the decimal + // point, then there is no fractional part, number is of the form: + // [<sign>]<significand>[<zeros>] + if (m_precision <= digitsBeforeDecimalPoint) { + if (m_sign) + ++length; + length += m_precision; + length += digitsBeforeDecimalPoint - m_precision; + return length; + } + + // If we get here, number starts before the decimal point, and ends after it, + // as such is of the form: + // [<sign>]<significand-begin>.<significand-end> + if (m_sign) + ++length; + length += digitsBeforeDecimalPoint; + ++length; // for decimal point + length += m_precision - digitsBeforeDecimalPoint; + + return length; +} + +unsigned DecimalNumber::bufferLengthForStringExponential() const +{ + unsigned length = 0; + if (m_sign) + ++length; + + // Add the significand + ++length; + + if (m_precision > 1) { + ++length; // for decimal point + length += m_precision - 1; + } + + // Add "e+" or "e-" + length += 2; + + int exponent = (m_exponent >= 0) ? m_exponent : -m_exponent; + + // Add the exponent + if (exponent >= 100) + ++length; + if (exponent >= 10) + ++length; + ++length; + + return length; +} + +unsigned DecimalNumber::toStringDecimal(UChar* buffer, unsigned bufferLength) const +{ + ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringDecimal()); + + // Should always be at least one digit to add to the string! + ASSERT(m_precision); + UChar* next = buffer; + + // if the exponent is negative the number decimal representation is of the form: + // [<sign>]0.[<zeros>]<significand> + if (m_exponent < 0) { + unsigned zeros = -m_exponent - 1; + + if (m_sign) + *next++ = '-'; + *next++ = '0'; + *next++ = '.'; + for (unsigned i = 0; i < zeros; ++i) + *next++ = '0'; + for (unsigned i = 0; i < m_precision; ++i) + *next++ = m_significand[i]; + + return next - buffer; + } + + unsigned digitsBeforeDecimalPoint = m_exponent + 1; + + // If the precision is <= than the number of digits to get up to the decimal + // point, then there is no fractional part, number is of the form: + // [<sign>]<significand>[<zeros>] + if (m_precision <= digitsBeforeDecimalPoint) { + if (m_sign) + *next++ = '-'; + for (unsigned i = 0; i < m_precision; ++i) + *next++ = m_significand[i]; + for (unsigned i = 0; i < (digitsBeforeDecimalPoint - m_precision); ++i) + *next++ = '0'; + + return next - buffer; + } + + // If we get here, number starts before the decimal point, and ends after it, + // as such is of the form: + // [<sign>]<significand-begin>.<significand-end> + + if (m_sign) + *next++ = '-'; + for (unsigned i = 0; i < digitsBeforeDecimalPoint; ++i) + *next++ = m_significand[i]; + *next++ = '.'; + for (unsigned i = digitsBeforeDecimalPoint; i < m_precision; ++i) + *next++ = m_significand[i]; + + return next - buffer; +} + +unsigned DecimalNumber::toStringExponential(UChar* buffer, unsigned bufferLength) const +{ + ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringExponential()); + + // Should always be at least one digit to add to the string! + ASSERT(m_precision); + UChar* next = buffer; + + // Add the sign + if (m_sign) + *next++ = '-'; + + // Add the significand + *next++ = m_significand[0]; + if (m_precision > 1) { + *next++ = '.'; + for (unsigned i = 1; i < m_precision; ++i) + *next++ = m_significand[i]; + } + + // Add "e+" or "e-" + *next++ = 'e'; + int exponent; + if (m_exponent >= 0) { + *next++ = '+'; + exponent = m_exponent; + } else { + *next++ = '-'; + exponent = -m_exponent; + } + + // Add the exponent + if (exponent >= 100) + *next++ = '0' + exponent / 100; + if (exponent >= 10) + *next++ = '0' + (exponent % 100) / 10; + *next++ = '0' + exponent % 10; + + return next - buffer; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/DecimalNumber.h b/JavaScriptCore/wtf/DecimalNumber.h new file mode 100644 index 0000000..c42f00b --- /dev/null +++ b/JavaScriptCore/wtf/DecimalNumber.h @@ -0,0 +1,108 @@ +/* + * 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 DecimalNumber_h +#define DecimalNumber_h + +#include <math.h> +#include <wtf/dtoa.h> +#include <wtf/MathExtras.h> +#include <wtf/text/WTFString.h> + +namespace WTF { + +enum RoundingSignificantFiguresType { RoundingSignificantFigures }; +enum RoundingDecimalPlacesType { RoundingDecimalPlaces }; + +class DecimalNumber { +public: + DecimalNumber(double d) + { + ASSERT(!isnan(d) && !isinf(d)); + dtoa(m_significand, d, m_sign, m_exponent, m_precision); + + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); + // No values other than zero should have a leading zero. + ASSERT(m_significand[0] != '0' || m_precision == 1); + // No values other than zero should have trailing zeros. + ASSERT(m_significand[0] == '0' || m_significand[m_precision - 1] != '0'); + } + + DecimalNumber(double d, RoundingSignificantFiguresType, unsigned significantFigures) + { + ASSERT(!isnan(d) && !isinf(d)); + dtoaRoundSF(m_significand, d, significantFigures, m_sign, m_exponent, m_precision); + + ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer)); + while (m_precision < significantFigures) + m_significand[m_precision++] = '0'; + + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); + } + + DecimalNumber(double d, RoundingDecimalPlacesType, unsigned decimalPlaces) + { + ASSERT(!isnan(d) && !isinf(d)); + dtoaRoundDP(m_significand, d, decimalPlaces, m_sign, m_exponent, m_precision); + + unsigned significantFigures = 1 + m_exponent + decimalPlaces; + ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer)); + while (m_precision < significantFigures) + m_significand[m_precision++] = '0'; + + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); + } + + unsigned bufferLengthForStringDecimal() const; + unsigned bufferLengthForStringExponential() const; + + unsigned toStringDecimal(UChar* buffer, unsigned bufferLength) const; + unsigned toStringExponential(UChar* buffer, unsigned bufferLength) const; + + bool sign() const { return m_sign; } + int exponent() const { return m_exponent; } + const char* significand() const { return m_significand; } // significand contains precision characters, is not null-terminated. + unsigned precision() const { return m_precision; } + +private: + bool m_sign; + int m_exponent; + DtoaBuffer m_significand; + unsigned m_precision; +}; + +} // namespace WTF + +using WTF::DecimalNumber; +using WTF::RoundingSignificantFigures; +using WTF::RoundingDecimalPlaces; + +#endif // DecimalNumber_h diff --git a/JavaScriptCore/wtf/Deque.h b/JavaScriptCore/wtf/Deque.h index 3c3d378..745e0b6 100644 --- a/JavaScriptCore/wtf/Deque.h +++ b/JavaScriptCore/wtf/Deque.h @@ -72,6 +72,7 @@ namespace WTF { T& first() { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; } const T& first() const { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; } + T takeFirst(); template<typename U> void append(const U&); template<typename U> void prepend(const U&); @@ -427,6 +428,14 @@ namespace WTF { checkValidity(); } + template<typename T> + inline T Deque<T>::takeFirst() + { + T oldFirst = first(); + removeFirst(); + return oldFirst; + } + template<typename T> template<typename U> inline void Deque<T>::append(const U& value) { diff --git a/JavaScriptCore/wtf/FastAllocBase.h b/JavaScriptCore/wtf/FastAllocBase.h index 81b1de0..bb1825e 100644 --- a/JavaScriptCore/wtf/FastAllocBase.h +++ b/JavaScriptCore/wtf/FastAllocBase.h @@ -85,38 +85,41 @@ namespace WTF { - class FastAllocBase { - public: - // Placement operator new. - void* operator new(size_t, void* p) { return p; } - void* operator new[](size_t, void* p) { return p; } - - void* operator new(size_t size) - { - void* p = fastMalloc(size); - fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNew); - return p; - } - - void operator delete(void* p) - { - fastMallocMatchValidateFree(p, Internal::AllocTypeClassNew); - fastFree(p); - } - - void* operator new[](size_t size) - { - void* p = fastMalloc(size); - fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNewArray); - return p; - } - - void operator delete[](void* p) - { - fastMallocMatchValidateFree(p, Internal::AllocTypeClassNewArray); - fastFree(p); - } - }; +#define WTF_MAKE_FAST_ALLOCATED \ +public: \ + void* operator new(size_t, void* p) { return p; } \ + void* operator new[](size_t, void* p) { return p; } \ + \ + void* operator new(size_t size) \ + { \ + void* p = ::WTF::fastMalloc(size); \ + ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNew); \ + return p; \ + } \ + \ + void operator delete(void* p) \ + { \ + ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNew); \ + ::WTF::fastFree(p); \ + } \ + \ + void* operator new[](size_t size) \ + { \ + void* p = ::WTF::fastMalloc(size); \ + ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNewArray); \ + return p; \ + } \ + \ + void operator delete[](void* p) \ + { \ + ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNewArray); \ + ::WTF::fastFree(p); \ + } \ +private: + +class FastAllocBase { + WTF_MAKE_FAST_ALLOCATED +}; // fastNew / fastDelete diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 79d2bfb..bbbdaf2 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -82,6 +82,7 @@ #if ENABLE(JSC_MULTIPLE_THREADS) #include <pthread.h> #endif +#include <wtf/StdLibExtras.h> #ifndef NO_TCMALLOC_SAMPLES #ifdef WTF_CHANGES @@ -204,6 +205,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 +376,22 @@ 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) && !PLATFORM(BREWMP) + // Brew MP uses its own memory allocator, so _msize does not work on the Brew MP simulator. + return _msize(const_cast<void*>(p)); +#else + return 1; +#endif +} + } // namespace WTF #if OS(DARWIN) @@ -394,24 +417,25 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #include "TCSpinLock.h" #include "TCSystemAlloc.h" #include <algorithm> -#include <errno.h> #include <limits> -#include <new> #include <pthread.h> #include <stdarg.h> #include <stddef.h> #include <stdio.h> +#if HAVE(ERRNO_H) +#include <errno.h> +#endif #if OS(UNIX) #include <unistd.h> #endif -#if COMPILER(MSVC) +#if OS(WINDOWS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #endif -#if WTF_CHANGES +#ifdef WTF_CHANGES #if OS(DARWIN) #include "MallocZoneSupport.h" @@ -460,7 +484,7 @@ namespace WTF { #define CHECK_CONDITION ASSERT #if OS(DARWIN) -class Span; +struct Span; class TCMalloc_Central_FreeListPadded; class TCMalloc_PageHeap; class TCMalloc_ThreadCache; @@ -995,7 +1019,7 @@ class PageHeapAllocator { if (!new_allocation) CRASH(); - *(void**)new_allocation = allocated_regions_; + *reinterpret_cast_ptr<void**>(new_allocation) = allocated_regions_; allocated_regions_ = new_allocation; free_area_ = new_allocation + kAlignedSize; free_avail_ = kAllocIncrement - kAlignedSize; @@ -1232,29 +1256,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 +1389,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 +1436,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 +1468,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; @@ -1463,11 +1493,23 @@ void TCMalloc_PageHeap::init() void TCMalloc_PageHeap::initializeScavenger() { - pthread_mutex_init(&m_scavengeMutex, 0); - pthread_cond_init(&m_scavengeCondition, 0); - m_scavengeThreadActive = true; - pthread_t thread; - pthread_create(&thread, 0, runScavengerThread, this); + // Create a non-recursive mutex. +#if !defined(PTHREAD_MUTEX_NORMAL) || PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT + pthread_mutex_init(&m_scavengeMutex, 0); +#else + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + + pthread_mutex_init(&m_scavengeMutex, &attr); + + pthread_mutexattr_destroy(&attr); +#endif + + pthread_cond_init(&m_scavengeCondition, 0); + m_scavengeThreadActive = true; + pthread_t thread; + pthread_create(&thread, 0, runScavengerThread, this); } void* TCMalloc_PageHeap::runScavengerThread(void* context) @@ -1481,8 +1523,10 @@ void* TCMalloc_PageHeap::runScavengerThread(void* context) ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger() { - if (!m_scavengeThreadActive && shouldContinueScavenging()) - pthread_cond_signal(&m_scavengeCondition); + // m_scavengeMutex should be held before accessing m_scavengeThreadActive. + ASSERT(pthread_mutex_trylock(m_scavengeMutex)); + if (!m_scavengeThreadActive && shouldScavenge()) + pthread_cond_signal(&m_scavengeCondition); } #else // !HAVE(DISPATCH_H) @@ -1491,58 +1535,55 @@ 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()) { - m_scavengingScheduled = true; - dispatch_resume(m_scavengeTimer); - } + ASSERT(IsHeld(pageheap_lock)); + if (!m_scavengingScheduled && shouldScavenge()) { + m_scavengingScheduled = true; + dispatch_resume(m_scavengeTimer); + } } #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 length = DLL_Length(&slist->normal); + size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? length : length / 2; + 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 +1612,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 +1676,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 +1708,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 +1830,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 +1996,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; @@ -2155,10 +2185,10 @@ class TCMalloc_ThreadCache { // Total byte size in cache size_t Size() const { return size_; } - void* Allocate(size_t size); + ALWAYS_INLINE void* Allocate(size_t size); void Deallocate(void* ptr, size_t size_class); - void FetchFromCentralCache(size_t cl, size_t allocationSize); + ALWAYS_INLINE void FetchFromCentralCache(size_t cl, size_t allocationSize); void ReleaseToCentralCache(size_t cl, int N); void Scavenge(); void Print() const; @@ -2259,12 +2289,12 @@ class TCMalloc_Central_FreeList { // REQUIRES: lock_ is held // Release an object to spans. // May temporarily release lock_. - void ReleaseToSpans(void* object); + ALWAYS_INLINE void ReleaseToSpans(void* object); // REQUIRES: lock_ is held // Populate cache by fetching from the page heap. // May temporarily release lock_. - void Populate(); + ALWAYS_INLINE void Populate(); // REQUIRES: lock is held. // Tries to make room for a TCEntry. If the cache is full it will try to @@ -2277,7 +2307,7 @@ class TCMalloc_Central_FreeList { // just iterates over the sizeclasses but does so without taking a lock. // Returns true on success. // May temporarily lock a "random" size class. - static bool EvictRandomSizeClass(size_t locked_size_class, bool force); + static ALWAYS_INLINE bool EvictRandomSizeClass(size_t locked_size_class, bool force); // REQUIRES: lock_ is *not* held. // Tries to shrink the Cache. If force is true it will relase objects to @@ -2328,7 +2358,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 +2393,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(); @@ -2383,15 +2413,13 @@ void TCMalloc_PageHeap::scavengerThread() void TCMalloc_PageHeap::periodicScavenge() { - { SpinLockHolder h(&pageheap_lock); pageheap->scavenge(); - } - if (!shouldContinueScavenging()) { - m_scavengingScheduled = false; - dispatch_suspend(m_scavengeTimer); - } + if (!shouldScavenge()) { + m_scavengingScheduled = false; + dispatch_suspend(m_scavengeTimer); + } } #endif // HAVE(DISPATCH_H) @@ -2677,7 +2705,13 @@ ALWAYS_INLINE void TCMalloc_Central_FreeList::Populate() { if (span) pageheap->RegisterSizeClass(span, size_class_); } if (span == NULL) { +#if HAVE(ERRNO_H) MESSAGE("allocation failed: %d\n", errno); +#elif OS(WINDOWS) + MESSAGE("allocation failed: %d\n", ::GetLastError()); +#else + MESSAGE("allocation failed\n"); +#endif lock_.Lock(); return; } @@ -2700,7 +2734,7 @@ ALWAYS_INLINE void TCMalloc_Central_FreeList::Populate() { char* nptr; while ((nptr = ptr + size) <= limit) { *tail = ptr; - tail = reinterpret_cast<void**>(ptr); + tail = reinterpret_cast_ptr<void**>(ptr); ptr = nptr; num++; } @@ -3044,7 +3078,7 @@ void TCMalloc_ThreadCache::BecomeIdle() { if (heap->in_setspecific_) return; // Do not disturb the active caller heap->in_setspecific_ = true; - pthread_setspecific(heap_key, NULL); + setThreadHeap(NULL); #ifdef HAVE_TLS // Also update the copy in __thread threadlocal_heap = NULL; @@ -3671,7 +3705,7 @@ extern "C" #define do_malloc do_malloc<crashOnFailure> template <bool crashOnFailure> -void* malloc(size_t); +ALWAYS_INLINE void* malloc(size_t); void* fastMalloc(size_t size) { @@ -3732,7 +3766,7 @@ void free(void* ptr) { extern "C" #else template <bool crashOnFailure> -void* calloc(size_t, size_t); +ALWAYS_INLINE void* calloc(size_t, size_t); void* fastCalloc(size_t n, size_t elem_size) { @@ -3796,7 +3830,7 @@ void cfree(void* ptr) { extern "C" #else template <bool crashOnFailure> -void* realloc(void*, size_t); +ALWAYS_INLINE void* realloc(void*, size_t); void* fastRealloc(void* old_ptr, size_t new_size) { @@ -3933,6 +3967,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 +4023,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 +4140,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; @@ -4385,9 +4478,12 @@ extern "C" { malloc_introspection_t jscore_fastmalloc_introspection = { &FastMallocZone::enumerate, &FastMallocZone::goodSize, &FastMallocZone::check, &FastMallocZone::print, &FastMallocZone::log, &FastMallocZone::forceLock, &FastMallocZone::forceUnlock, &FastMallocZone::statistics -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !OS(IPHONE_OS) +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) , 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher. #endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + , 0, 0, 0, 0 // These members will not be used unless the zone advertises itself as version seven or higher. +#endif }; } @@ -4419,44 +4515,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..9729bc3 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; @@ -206,7 +207,7 @@ using WTF::fastMallocAllow; #define WTF_PRIVATE_INLINE inline #endif -#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC) +#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC && !PLATFORM(BREWMP)) // The nothrow functions here are actually not all that helpful, because fastMalloc will // call CRASH() rather than returning 0, and returning 0 is what nothrow is all about. @@ -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/FixedArray.h b/JavaScriptCore/wtf/FixedArray.h new file mode 100644 index 0000000..c67d18c --- /dev/null +++ b/JavaScriptCore/wtf/FixedArray.h @@ -0,0 +1,58 @@ +/* + * 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. 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 INC. 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 FixedArray_h +#define FixedArray_h + +#include <wtf/Assertions.h> + +namespace WTF { + +template <typename T, size_t Size> class FixedArray { +public: + T& operator[](size_t i) + { + ASSERT(i < Size); + return m_data[i]; + } + + const T& operator[](size_t i) const + { + ASSERT(i < Size); + return m_data[i]; + } + + T* data() { return m_data; } + size_t size() const { return Size; } + +private: + T m_data[Size]; +}; + +} // namespace WTF + +using WTF::FixedArray; + +#endif // FixedArray_h diff --git a/JavaScriptCore/wtf/Forward.h b/JavaScriptCore/wtf/Forward.h index 448de7d..3a9cfa7 100644 --- a/JavaScriptCore/wtf/Forward.h +++ b/JavaScriptCore/wtf/Forward.h @@ -27,18 +27,34 @@ namespace WTF { template<typename T> class ListRefPtr; template<typename T> class OwnArrayPtr; template<typename T> class OwnPtr; + template<typename T> class PassOwnArrayPtr; template<typename T> class PassOwnPtr; template<typename T> class PassRefPtr; template<typename T> class RefPtr; template<typename T, size_t inlineCapacity> class Vector; + + class AtomicString; + class AtomicStringImpl; + class CString; + class String; + class StringBuffer; + class StringImpl; } using WTF::ListRefPtr; using WTF::OwnArrayPtr; using WTF::OwnPtr; +using WTF::PassOwnArrayPtr; using WTF::PassOwnPtr; using WTF::PassRefPtr; using WTF::RefPtr; using WTF::Vector; +using WTF::AtomicString; +using WTF::AtomicStringImpl; +using WTF::CString; +using WTF::String; +using WTF::StringBuffer; +using WTF::StringImpl; + #endif // WTF_Forward_h 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/HashSet.h b/JavaScriptCore/wtf/HashSet.h index 4429490..66639e4 100644 --- a/JavaScriptCore/wtf/HashSet.h +++ b/JavaScriptCore/wtf/HashSet.h @@ -48,7 +48,7 @@ namespace WTF { HashFunctions, ValueTraits, ValueTraits> HashTableType; public: - typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator; + typedef HashTableConstIteratorAdapter<HashTableType, ValueType> iterator; typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator; void swap(HashSet&); @@ -57,13 +57,10 @@ namespace WTF { int capacity() const; bool isEmpty() const; - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; + iterator begin() const; + iterator end() const; - iterator find(const ValueType&); - const_iterator find(const ValueType&) const; + iterator find(const ValueType&) const; bool contains(const ValueType&) const; // An alternate version of find() that finds the object by hashing and comparing @@ -71,8 +68,7 @@ namespace WTF { // must have the following function members: // static unsigned hash(const T&); // static bool equal(const ValueType&, const T&); - template<typename T, typename HashTranslator> iterator find(const T&); - template<typename T, typename HashTranslator> const_iterator find(const T&) const; + template<typename T, typename HashTranslator> iterator find(const T&) const; template<typename T, typename HashTranslator> bool contains(const T&) const; // The return value is a pair of an interator to the new value's location, @@ -137,37 +133,19 @@ namespace WTF { } template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::begin() + inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::begin() const { return m_impl.begin(); } template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::end() + inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::end() const { return m_impl.end(); } template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::begin() const - { - return m_impl.begin(); - } - - template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::end() const - { - return m_impl.end(); - } - - template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::find(const ValueType& value) - { - return m_impl.find(value); - } - - template<typename T, typename U, typename V> - inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::find(const ValueType& value) const + inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::find(const ValueType& value) const { return m_impl.find(value); } @@ -181,15 +159,6 @@ namespace WTF { template<typename Value, typename HashFunctions, typename Traits> template<typename T, typename HashTranslator> typename HashSet<Value, HashFunctions, Traits>::iterator - inline HashSet<Value, HashFunctions, Traits>::find(const T& value) - { - typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, HashTranslator> Adapter; - return m_impl.template find<T, Adapter>(value); - } - - template<typename Value, typename HashFunctions, typename Traits> - template<typename T, typename HashTranslator> - typename HashSet<Value, HashFunctions, Traits>::const_iterator inline HashSet<Value, HashFunctions, Traits>::find(const T& value) const { typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, HashTranslator> Adapter; diff --git a/JavaScriptCore/wtf/HashTable.h b/JavaScriptCore/wtf/HashTable.h index ceb8963..1c4ae6d 100644 --- a/JavaScriptCore/wtf/HashTable.h +++ b/JavaScriptCore/wtf/HashTable.h @@ -333,6 +333,7 @@ namespace WTF { void remove(const KeyType&); void remove(iterator); void removeWithoutEntryConsistencyCheck(iterator); + void removeWithoutEntryConsistencyCheck(const_iterator); void clear(); static bool isEmptyBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::emptyValue(); } @@ -854,6 +855,15 @@ namespace WTF { } template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> + inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeWithoutEntryConsistencyCheck(const_iterator it) + { + if (it == end()) + return; + + removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_position)); + } + + template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(const KeyType& key) { remove(find(key)); diff --git a/JavaScriptCore/wtf/ListHashSet.h b/JavaScriptCore/wtf/ListHashSet.h index 54ed36b..e14ac45 100644 --- a/JavaScriptCore/wtf/ListHashSet.h +++ b/JavaScriptCore/wtf/ListHashSet.h @@ -24,6 +24,7 @@ #include "Assertions.h" #include "HashSet.h" #include "OwnPtr.h" +#include "StdLibExtras.h" namespace WTF { @@ -37,27 +38,27 @@ namespace WTF { // and an append that moves the element to the end even if already present, // but unclear yet if these are needed. - template<typename Value, typename HashFunctions> class ListHashSet; + template<typename Value, size_t inlineCapacity, typename HashFunctions> class ListHashSet; template<typename T> struct IdentityExtractor; - template<typename Value, typename HashFunctions> - void deleteAllValues(const ListHashSet<Value, HashFunctions>&); + template<typename Value, size_t inlineCapacity, typename HashFunctions> + void deleteAllValues(const ListHashSet<Value, inlineCapacity, HashFunctions>&); - template<typename ValueArg, typename HashArg> class ListHashSetIterator; - template<typename ValueArg, typename HashArg> class ListHashSetConstIterator; + template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator; + template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator; - template<typename ValueArg> struct ListHashSetNode; - template<typename ValueArg> struct ListHashSetNodeAllocator; - template<typename ValueArg, typename HashArg> struct ListHashSetNodeHashFunctions; + template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode; + template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator; + template<typename ValueArg, size_t inlineCapacity, typename HashArg> struct ListHashSetNodeHashFunctions; - template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet : public FastAllocBase { + template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet : public FastAllocBase { private: - typedef ListHashSetNode<ValueArg> Node; - typedef ListHashSetNodeAllocator<ValueArg> NodeAllocator; + typedef ListHashSetNode<ValueArg, inlineCapacity> Node; + typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; typedef HashTraits<Node*> NodeTraits; - typedef ListHashSetNodeHashFunctions<ValueArg, HashArg> NodeHash; + typedef ListHashSetNodeHashFunctions<ValueArg, inlineCapacity, HashArg> NodeHash; typedef HashTable<Node*, Node*, IdentityExtractor<Node*>, NodeHash, NodeTraits, NodeTraits> ImplType; typedef HashTableIterator<Node*, Node*, IdentityExtractor<Node*>, NodeHash, NodeTraits, NodeTraits> ImplTypeIterator; @@ -67,10 +68,10 @@ namespace WTF { public: typedef ValueArg ValueType; - typedef ListHashSetIterator<ValueType, HashArg> iterator; - typedef ListHashSetConstIterator<ValueType, HashArg> const_iterator; + typedef ListHashSetIterator<ValueType, inlineCapacity, HashArg> iterator; + typedef ListHashSetConstIterator<ValueType, inlineCapacity, HashArg> const_iterator; - friend class ListHashSetConstIterator<ValueType, HashArg>; + friend class ListHashSetConstIterator<ValueType, inlineCapacity, HashArg>; ListHashSet(); ListHashSet(const ListHashSet&); @@ -119,9 +120,9 @@ namespace WTF { OwnPtr<NodeAllocator> m_allocator; }; - template<typename ValueArg> struct ListHashSetNodeAllocator { - typedef ListHashSetNode<ValueArg> Node; - typedef ListHashSetNodeAllocator<ValueArg> NodeAllocator; + template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator { + typedef ListHashSetNode<ValueArg, inlineCapacity> Node; + typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; ListHashSetNodeAllocator() : m_freeList(pool()) @@ -171,7 +172,7 @@ namespace WTF { } private: - Node* pool() { return reinterpret_cast<Node*>(m_pool.pool); } + Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.pool); } Node* pastPool() { return pool() + m_poolSize; } bool inPool(Node* node) @@ -181,15 +182,15 @@ namespace WTF { Node* m_freeList; bool m_isDoneWithInitialFreeList; - static const size_t m_poolSize = 256; + static const size_t m_poolSize = inlineCapacity; union { char pool[sizeof(Node) * m_poolSize]; double forAlignment; } m_pool; }; - template<typename ValueArg> struct ListHashSetNode { - typedef ListHashSetNodeAllocator<ValueArg> NodeAllocator; + template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode { + typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator; ListHashSetNode(ValueArg value) : m_value(value) @@ -220,25 +221,25 @@ namespace WTF { #endif }; - template<typename ValueArg, typename HashArg> struct ListHashSetNodeHashFunctions { - typedef ListHashSetNode<ValueArg> Node; + template<typename ValueArg, size_t inlineCapacity, typename HashArg> struct ListHashSetNodeHashFunctions { + typedef ListHashSetNode<ValueArg, inlineCapacity> Node; static unsigned hash(Node* const& key) { return HashArg::hash(key->m_value); } static bool equal(Node* const& a, Node* const& b) { return HashArg::equal(a->m_value, b->m_value); } static const bool safeToCompareToEmptyOrDeleted = false; }; - template<typename ValueArg, typename HashArg> class ListHashSetIterator { + template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator { private: - typedef ListHashSet<ValueArg, HashArg> ListHashSetType; - typedef ListHashSetIterator<ValueArg, HashArg> iterator; - typedef ListHashSetConstIterator<ValueArg, HashArg> const_iterator; - typedef ListHashSetNode<ValueArg> Node; + typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; + typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; + typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; + typedef ListHashSetNode<ValueArg, inlineCapacity> Node; typedef ValueArg ValueType; typedef ValueType& ReferenceType; typedef ValueType* PointerType; - friend class ListHashSet<ValueArg, HashArg>; + friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; ListHashSetIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { } @@ -271,18 +272,18 @@ namespace WTF { const_iterator m_iterator; }; - template<typename ValueArg, typename HashArg> class ListHashSetConstIterator { + template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator { private: - typedef ListHashSet<ValueArg, HashArg> ListHashSetType; - typedef ListHashSetIterator<ValueArg, HashArg> iterator; - typedef ListHashSetConstIterator<ValueArg, HashArg> const_iterator; - typedef ListHashSetNode<ValueArg> Node; + typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType; + typedef ListHashSetIterator<ValueArg, inlineCapacity, HashArg> iterator; + typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_iterator; + typedef ListHashSetNode<ValueArg, inlineCapacity> Node; typedef ValueArg ValueType; typedef const ValueType& ReferenceType; typedef const ValueType* PointerType; - friend class ListHashSet<ValueArg, HashArg>; - friend class ListHashSetIterator<ValueArg, HashArg>; + friend class ListHashSet<ValueArg, inlineCapacity, HashArg>; + friend class ListHashSetIterator<ValueArg, inlineCapacity, HashArg>; ListHashSetConstIterator(const ListHashSetType* set, Node* position) : m_set(set) @@ -341,11 +342,11 @@ namespace WTF { }; - template<typename ValueType, typename HashFunctions> + template<typename ValueType, size_t inlineCapacity, typename HashFunctions> struct ListHashSetTranslator { private: - typedef ListHashSetNode<ValueType> Node; - typedef ListHashSetNodeAllocator<ValueType> NodeAllocator; + typedef ListHashSetNode<ValueType, inlineCapacity> Node; + typedef ListHashSetNodeAllocator<ValueType, inlineCapacity> NodeAllocator; public: static unsigned hash(const ValueType& key) { return HashFunctions::hash(key); } static bool equal(Node* const& a, const ValueType& b) { return HashFunctions::equal(a->m_value, b); } @@ -355,16 +356,16 @@ namespace WTF { } }; - template<typename T, typename U> - inline ListHashSet<T, U>::ListHashSet() + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSet<T, inlineCapacity, U>::ListHashSet() : m_head(0) , m_tail(0) , m_allocator(new NodeAllocator) { } - template<typename T, typename U> - inline ListHashSet<T, U>::ListHashSet(const ListHashSet& other) + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSet<T, inlineCapacity, U>::ListHashSet(const ListHashSet& other) : m_head(0) , m_tail(0) , m_allocator(new NodeAllocator) @@ -374,16 +375,16 @@ namespace WTF { add(*it); } - template<typename T, typename U> - inline ListHashSet<T, U>& ListHashSet<T, U>::operator=(const ListHashSet& other) + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSet<T, inlineCapacity, U>& ListHashSet<T, inlineCapacity, U>::operator=(const ListHashSet& other) { ListHashSet tmp(other); swap(tmp); return *this; } - template<typename T, typename U> - inline void ListHashSet<T, U>::swap(ListHashSet& other) + template<typename T, size_t inlineCapacity, typename U> + inline void ListHashSet<T, inlineCapacity, U>::swap(ListHashSet& other) { m_impl.swap(other.m_impl); std::swap(m_head, other.m_head); @@ -391,95 +392,95 @@ namespace WTF { m_allocator.swap(other.m_allocator); } - template<typename T, typename U> - inline ListHashSet<T, U>::~ListHashSet() + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSet<T, inlineCapacity, U>::~ListHashSet() { deleteAllNodes(); } - template<typename T, typename U> - inline int ListHashSet<T, U>::size() const + template<typename T, size_t inlineCapacity, typename U> + inline int ListHashSet<T, inlineCapacity, U>::size() const { return m_impl.size(); } - template<typename T, typename U> - inline int ListHashSet<T, U>::capacity() const + template<typename T, size_t inlineCapacity, typename U> + inline int ListHashSet<T, inlineCapacity, U>::capacity() const { return m_impl.capacity(); } - template<typename T, typename U> - inline bool ListHashSet<T, U>::isEmpty() const + template<typename T, size_t inlineCapacity, typename U> + inline bool ListHashSet<T, inlineCapacity, U>::isEmpty() const { return m_impl.isEmpty(); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::iterator ListHashSet<T, U>::begin() + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::begin() { return makeIterator(m_head); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::iterator ListHashSet<T, U>::end() + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::end() { return makeIterator(0); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::const_iterator ListHashSet<T, U>::begin() const + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::begin() const { return makeConstIterator(m_head); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::const_iterator ListHashSet<T, U>::end() const + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::end() const { return makeConstIterator(0); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::iterator ListHashSet<T, U>::find(const ValueType& value) + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) { - typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; ImplTypeIterator it = m_impl.template find<ValueType, Translator>(value); if (it == m_impl.end()) return end(); return makeIterator(*it); } - template<typename T, typename U> - inline typename ListHashSet<T, U>::const_iterator ListHashSet<T, U>::find(const ValueType& value) const + template<typename T, size_t inlineCapacity, typename U> + inline typename ListHashSet<T, inlineCapacity, U>::const_iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value) const { - typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; ImplTypeConstIterator it = m_impl.template find<ValueType, Translator>(value); if (it == m_impl.end()) return end(); return makeConstIterator(*it); } - template<typename T, typename U> - inline bool ListHashSet<T, U>::contains(const ValueType& value) const + template<typename T, size_t inlineCapacity, typename U> + inline bool ListHashSet<T, inlineCapacity, U>::contains(const ValueType& value) const { - typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; return m_impl.template contains<ValueType, Translator>(value); } - template<typename T, typename U> - pair<typename ListHashSet<T, U>::iterator, bool> ListHashSet<T, U>::add(const ValueType &value) + template<typename T, size_t inlineCapacity, typename U> + pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::add(const ValueType &value) { - typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; pair<typename ImplType::iterator, bool> result = m_impl.template add<ValueType, NodeAllocator*, Translator>(value, m_allocator.get()); if (result.second) appendNode(*result.first); return std::make_pair(makeIterator(*result.first), result.second); } - template<typename T, typename U> - pair<typename ListHashSet<T, U>::iterator, bool> ListHashSet<T, U>::insertBefore(iterator it, const ValueType& newValue) + template<typename T, size_t inlineCapacity, typename U> + pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::insertBefore(iterator it, const ValueType& newValue) { - typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + typedef ListHashSetTranslator<ValueType, inlineCapacity, HashFunctions> Translator; pair<typename ImplType::iterator, bool> result = m_impl.template add<ValueType, NodeAllocator*, Translator>(newValue, m_allocator.get()); if (result.second) insertNodeBefore(it.node(), *result.first); @@ -487,14 +488,14 @@ namespace WTF { } - template<typename T, typename U> - pair<typename ListHashSet<T, U>::iterator, bool> ListHashSet<T, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) + template<typename T, size_t inlineCapacity, typename U> + pair<typename ListHashSet<T, inlineCapacity, U>::iterator, bool> ListHashSet<T, inlineCapacity, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) { return insertBefore(find(beforeValue), newValue); } - template<typename T, typename U> - inline void ListHashSet<T, U>::remove(iterator it) + template<typename T, size_t inlineCapacity, typename U> + inline void ListHashSet<T, inlineCapacity, U>::remove(iterator it) { if (it == end()) return; @@ -502,14 +503,14 @@ namespace WTF { unlinkAndDelete(it.node()); } - template<typename T, typename U> - inline void ListHashSet<T, U>::remove(const ValueType& value) + template<typename T, size_t inlineCapacity, typename U> + inline void ListHashSet<T, inlineCapacity, U>::remove(const ValueType& value) { remove(find(value)); } - template<typename T, typename U> - inline void ListHashSet<T, U>::clear() + template<typename T, size_t inlineCapacity, typename U> + inline void ListHashSet<T, inlineCapacity, U>::clear() { deleteAllNodes(); m_impl.clear(); @@ -517,8 +518,8 @@ namespace WTF { m_tail = 0; } - template<typename T, typename U> - void ListHashSet<T, U>::unlinkAndDelete(Node* node) + template<typename T, size_t inlineCapacity, typename U> + void ListHashSet<T, inlineCapacity, U>::unlinkAndDelete(Node* node) { if (!node->m_prev) { ASSERT(node == m_head); @@ -539,8 +540,8 @@ namespace WTF { node->destroy(m_allocator.get()); } - template<typename T, typename U> - void ListHashSet<T, U>::appendNode(Node* node) + template<typename T, size_t inlineCapacity, typename U> + void ListHashSet<T, inlineCapacity, U>::appendNode(Node* node) { node->m_prev = m_tail; node->m_next = 0; @@ -556,8 +557,8 @@ namespace WTF { m_tail = node; } - template<typename T, typename U> - void ListHashSet<T, U>::insertNodeBefore(Node* beforeNode, Node* newNode) + template<typename T, size_t inlineCapacity, typename U> + void ListHashSet<T, inlineCapacity, U>::insertNodeBefore(Node* beforeNode, Node* newNode) { if (!beforeNode) return appendNode(newNode); @@ -572,8 +573,8 @@ namespace WTF { m_head = newNode; } - template<typename T, typename U> - void ListHashSet<T, U>::deleteAllNodes() + template<typename T, size_t inlineCapacity, typename U> + void ListHashSet<T, inlineCapacity, U>::deleteAllNodes() { if (!m_head) return; @@ -582,16 +583,16 @@ namespace WTF { node->destroy(m_allocator.get()); } - template<typename T, typename U> - inline ListHashSetIterator<T, U> ListHashSet<T, U>::makeIterator(Node* position) + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSetIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeIterator(Node* position) { - return ListHashSetIterator<T, U>(this, position); + return ListHashSetIterator<T, inlineCapacity, U>(this, position); } - template<typename T, typename U> - inline ListHashSetConstIterator<T, U> ListHashSet<T, U>::makeConstIterator(Node* position) const + template<typename T, size_t inlineCapacity, typename U> + inline ListHashSetConstIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstIterator(Node* position) const { - return ListHashSetConstIterator<T, U>(this, position); + return ListHashSetConstIterator<T, inlineCapacity, U>(this, position); } template<bool, typename ValueType, typename HashTableType> @@ -603,10 +604,10 @@ namespace WTF { delete (*it)->m_value; } - template<typename T, typename U> - inline void deleteAllValues(const ListHashSet<T, U>& collection) + template<typename T, size_t inlineCapacity, typename U> + inline void deleteAllValues(const ListHashSet<T, inlineCapacity, U>& collection) { - deleteAllValues<true, typename ListHashSet<T, U>::ValueType>(collection.m_impl); + deleteAllValues<true, typename ListHashSet<T, inlineCapacity, U>::ValueType>(collection.m_impl); } } // namespace WTF diff --git a/JavaScriptCore/wtf/MD5.cpp b/JavaScriptCore/wtf/MD5.cpp new file mode 100644 index 0000000..c926a7b --- /dev/null +++ b/JavaScriptCore/wtf/MD5.cpp @@ -0,0 +1,308 @@ +// 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 +#include <wtf/StdLibExtras.h> + +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(digest); + 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[%lu] actual:%s expected:%s", input.data(), static_cast<unsigned long>(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_ptr<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_ptr<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_ptr<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); +} + +void MD5::checksum(Vector<uint8_t, 16>& digest) +{ + // 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_ptr<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_ptr<uint32_t*>(m_in))[14] = m_bits[0]; + (reinterpret_cast_ptr<uint32_t*>(m_in))[15] = m_bits[1]; + + MD5Transform(m_buf, reinterpret_cast_ptr<uint32_t*>(m_in)); + reverseBytes(reinterpret_cast<uint8_t*>(m_buf), 4); + + // Now, m_buf contains checksum result. + if (!digest.isEmpty()) + digest.clear(); + 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)); +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/MD5.h b/JavaScriptCore/wtf/MD5.h new file mode 100644 index 0000000..3caa810 --- /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. + void checksum(Vector<uint8_t, 16>&); + +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..a5f2346 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 { @@ -47,13 +51,30 @@ struct FunctionWithContext { , syncFlag(syncFlag) { } + bool operator == (const FunctionWithContext& o) + { + return function == o.function + && context == o.context + && syncFlag == o.syncFlag; + } }; +class FunctionWithContextFinder { +public: + FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {} + bool operator() (FunctionWithContext& o) { return o == m; } + FunctionWithContext m; +}; + + 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 +86,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; @@ -89,8 +149,7 @@ void dispatchFunctionsFromMainThread() MutexLocker locker(mainThreadFunctionQueueMutex()); if (!functionQueue().size()) break; - invocation = functionQueue().first(); - functionQueue().removeFirst(); + invocation = functionQueue().takeFirst(); } invocation.function(invocation.context); @@ -139,6 +198,24 @@ void callOnMainThreadAndWait(MainThreadFunction* function, void* context) syncFlag.wait(functionQueueMutex); } +void cancelCallOnMainThread(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + MutexLocker locker(mainThreadFunctionQueueMutex()); + + FunctionWithContextFinder pred(FunctionWithContext(function, context)); + + while (true) { + // We must redefine 'i' each pass, because the itererator's operator= + // requires 'this' to be valid, and remove() invalidates all iterators + FunctionQueue::iterator i(functionQueue().findIf(pred)); + if (i == functionQueue().end()) + break; + functionQueue().remove(i); + } +} + void setMainThreadCallbacksPaused(bool paused) { ASSERT(isMainThread()); @@ -152,4 +229,11 @@ void setMainThreadCallbacksPaused(bool paused) scheduleDispatchFunctionsOnMainThread(); } +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(BREWMP) +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} +#endif + } // namespace WTF diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h index 8c0275b..7703f3e 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,42 @@ #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 cancelCallOnMainThread(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::cancelCallOnMainThread; using WTF::setMainThreadCallbacksPaused; - +using WTF::isMainThread; #endif // MainThread_h diff --git a/JavaScriptCore/wtf/MathExtras.h b/JavaScriptCore/wtf/MathExtras.h index 8e93ee8..8a8741c 100644 --- a/JavaScriptCore/wtf/MathExtras.h +++ b/JavaScriptCore/wtf/MathExtras.h @@ -54,6 +54,14 @@ const double piDouble = M_PI; const float piFloat = static_cast<float>(M_PI); #endif +#ifndef M_PI_2 +const double piOverTwoDouble = 1.57079632679489661923; +const float piOverTwoFloat = 1.57079632679489661923f; +#else +const double piOverTwoDouble = M_PI_2; +const float piOverTwoFloat = static_cast<float>(M_PI_2); +#endif + #ifndef M_PI_4 const double piOverFourDouble = 0.785398163397448309616; const float piOverFourFloat = 0.785398163397448309616f; @@ -122,6 +130,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 +198,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) || PLATFORM(BREWMP))) using std::isfinite; using std::isinf; using std::isnan; diff --git a/JavaScriptCore/wtf/MessageQueue.h b/JavaScriptCore/wtf/MessageQueue.h index 48bd10a..14100c9 100644 --- a/JavaScriptCore/wtf/MessageQueue.h +++ b/JavaScriptCore/wtf/MessageQueue.h @@ -92,7 +92,7 @@ namespace WTF { inline void MessageQueue<DataType>::append(PassOwnPtr<DataType> message) { MutexLocker lock(m_mutex); - m_queue.append(message.release()); + m_queue.append(message.leakPtr()); m_condition.signal(); } @@ -102,7 +102,7 @@ namespace WTF { { MutexLocker lock(m_mutex); bool wasEmpty = m_queue.isEmpty(); - m_queue.append(message.release()); + m_queue.append(message.leakPtr()); m_condition.signal(); return wasEmpty; } @@ -111,7 +111,7 @@ namespace WTF { inline void MessageQueue<DataType>::prepend(PassOwnPtr<DataType> message) { MutexLocker lock(m_mutex); - m_queue.prepend(message.release()); + m_queue.prepend(message.leakPtr()); m_condition.signal(); } @@ -163,9 +163,7 @@ namespace WTF { if (m_queue.isEmpty()) return 0; - DataType* message = m_queue.first(); - m_queue.removeFirst(); - return message; + return m_queue.takeFirst(); } template<typename DataType> diff --git a/JavaScriptCore/wtf/NonCopyingSort.h b/JavaScriptCore/wtf/NonCopyingSort.h new file mode 100644 index 0000000..fd611bd --- /dev/null +++ b/JavaScriptCore/wtf/NonCopyingSort.h @@ -0,0 +1,89 @@ +/* + * 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 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 WTF_NonCopyingSort_h +#define WTF_NonCopyingSort_h + +namespace WTF { + +using std::swap; + +template<typename RandomAccessIterator, typename Predicate> +inline void siftDown(RandomAccessIterator array, ptrdiff_t start, ptrdiff_t end, Predicate compareLess) +{ + ptrdiff_t root = start; + + while (root * 2 + 1 <= end) { + ptrdiff_t child = root * 2 + 1; + if (child < end && compareLess(array[child], array[child + 1])) + child++; + + if (compareLess(array[root], array[child])) { + swap(array[root], array[child]); + root = child; + } else + return; + } +} + +template<typename RandomAccessIterator, typename Predicate> +inline void heapify(RandomAccessIterator array, ptrdiff_t count, Predicate compareLess) +{ + ptrdiff_t start = (count - 2) / 2; + + while (start >= 0) { + siftDown(array, start, count - 1, compareLess); + start--; + } +} + +template<typename RandomAccessIterator, typename Predicate> +void heapSort(RandomAccessIterator start, RandomAccessIterator end, Predicate compareLess) +{ + ptrdiff_t count = end - start; + heapify(start, count, compareLess); + + ptrdiff_t endIndex = count - 1; + while (endIndex > 0) { + swap(start[endIndex], start[0]); + siftDown(start, 0, endIndex - 1, compareLess); + endIndex--; + } +} + +template<typename RandomAccessIterator, typename Predicate> +inline void nonCopyingSort(RandomAccessIterator start, RandomAccessIterator end, Predicate compareLess) +{ + // heapsort happens to use only swaps, not copies, but the essential thing about + // this function is the fact that it does not copy, not the specific algorithm + heapSort(start, end, compareLess); +} + +} // namespace WTF + +using WTF::nonCopyingSort; + +#endif // WTF_NonCopyingSort_h diff --git a/JavaScriptCore/wtf/Noncopyable.h b/JavaScriptCore/wtf/Noncopyable.h index 60a46e2..285ed2e 100644 --- a/JavaScriptCore/wtf/Noncopyable.h +++ b/JavaScriptCore/wtf/Noncopyable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2010 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 @@ -21,6 +21,26 @@ #ifndef WTF_Noncopyable_h #define WTF_Noncopyable_h +#ifndef __has_feature + #define __has_feature(x) 0 +#endif + +#if __has_feature(cxx_deleted_functions) + #define WTF_MAKE_NONCOPYABLE(ClassName) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \ + _Pragma("clang diagnostic ignored \"-Wc++0x-extensions\"") \ + private: \ + ClassName(const ClassName&) = delete; \ + ClassName& operator=(const ClassName&) = delete; \ + _Pragma("clang diagnostic pop") +#else + #define WTF_MAKE_NONCOPYABLE(ClassName) \ + private: \ + ClassName(const ClassName&); \ + ClassName& operator=(const ClassName&) +#endif + // We don't want argument-dependent lookup to pull in everything from the WTF // namespace when you use Noncopyable, so put it in its own namespace. @@ -36,17 +56,8 @@ namespace WTFNoncopyable { ~Noncopyable() { } }; - class NoncopyableCustomAllocated { - NoncopyableCustomAllocated(const NoncopyableCustomAllocated&); - NoncopyableCustomAllocated& operator=(const NoncopyableCustomAllocated&); - protected: - NoncopyableCustomAllocated() { } - ~NoncopyableCustomAllocated() { } - }; - } // namespace WTFNoncopyable using WTFNoncopyable::Noncopyable; -using WTFNoncopyable::NoncopyableCustomAllocated; #endif // WTF_Noncopyable_h diff --git a/JavaScriptCore/wtf/NullPtr.cpp b/JavaScriptCore/wtf/NullPtr.cpp new file mode 100644 index 0000000..e7d94b2 --- /dev/null +++ b/JavaScriptCore/wtf/NullPtr.cpp @@ -0,0 +1,33 @@ +/* + +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. 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 INC. 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 "NullPtr.h" + +#if !__has_feature(cxx_nullptr) + +std::nullptr_t nullptr; + +#endif diff --git a/JavaScriptCore/wtf/NullPtr.h b/JavaScriptCore/wtf/NullPtr.h new file mode 100644 index 0000000..10a5814 --- /dev/null +++ b/JavaScriptCore/wtf/NullPtr.h @@ -0,0 +1,48 @@ +/* + +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. 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 INC. 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 NullPtr_h +#define NullPtr_h + +// For compilers and standard libraries that do not yet include it, this adds the +// nullptr_t type and nullptr object. They are defined in the same namespaces they +// would be in compiler and library that had the support. + +#ifndef __has_feature + #define __has_feature(feature) 0 +#endif + +#if !__has_feature(cxx_nullptr) + +namespace std { + class nullptr_t { }; +} + +extern std::nullptr_t nullptr; + +#endif + +#endif diff --git a/JavaScriptCore/wtf/OwnArrayPtr.h b/JavaScriptCore/wtf/OwnArrayPtr.h index 61375c7..643b90b 100644 --- a/JavaScriptCore/wtf/OwnArrayPtr.h +++ b/JavaScriptCore/wtf/OwnArrayPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2010 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 @@ -21,52 +21,156 @@ #ifndef WTF_OwnArrayPtr_h #define WTF_OwnArrayPtr_h +#include "Assertions.h" +#include "Noncopyable.h" +#include "NullPtr.h" +#include "OwnArrayPtrCommon.h" #include <algorithm> -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> + +// Remove this once we make all WebKit code compatible with stricter rules about OwnArrayPtr. +#define LOOSE_OWN_ARRAY_PTR namespace WTF { - template <typename T> class OwnArrayPtr : public Noncopyable { - public: - explicit OwnArrayPtr(T* ptr = 0) : m_ptr(ptr) { } - ~OwnArrayPtr() { safeDelete(); } +template<typename T> class PassOwnArrayPtr; +template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*); + +template <typename T> class OwnArrayPtr : public Noncopyable { +public: + typedef T* PtrType; + + OwnArrayPtr() : m_ptr(0) { } + + // See comment in PassOwnArrayPtr.h for why this takes a const reference. + template<typename U> OwnArrayPtr(const PassOwnArrayPtr<U>& o); + + // This copy constructor is used implicitly by gcc when it generates + // transients for assigning a PassOwnArrayPtr<T> object to a stack-allocated + // OwnArrayPtr<T> object. It should never be called explicitly and gcc + // should optimize away the constructor when generating code. + OwnArrayPtr(const OwnArrayPtr<T>&); - T* get() const { return m_ptr; } - T* release() { T* ptr = m_ptr; m_ptr = 0; return ptr; } + ~OwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); } - void set(T* ptr) { ASSERT(m_ptr != ptr); safeDelete(); m_ptr = ptr; } - void clear() { safeDelete(); m_ptr = 0; } + PtrType get() const { return m_ptr; } - T& operator*() const { ASSERT(m_ptr); return *m_ptr; } - T* operator->() const { ASSERT(m_ptr); return m_ptr; } + void clear(); + PassOwnArrayPtr<T> release(); + PtrType leakPtr() WARN_UNUSED_RETURN; - T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; } + T& operator*() const { ASSERT(m_ptr); return *m_ptr; } + PtrType operator->() const { ASSERT(m_ptr); return m_ptr; } - bool operator!() const { return !m_ptr; } + T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; } - // This conversion operator allows implicit conversion to bool but not to other integer types. + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. #if COMPILER(WINSCW) - operator bool() const { return m_ptr; } + operator bool() const { return m_ptr; } #else - typedef T* OwnArrayPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; } + typedef T* OwnArrayPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; } #endif - void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); } + OwnArrayPtr& operator=(const PassOwnArrayPtr<T>&); + OwnArrayPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> OwnArrayPtr& operator=(const PassOwnArrayPtr<U>&); + + void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); } - private: - void safeDelete() { typedef char known[sizeof(T) ? 1 : -1]; if (sizeof(known)) delete [] m_ptr; } +#ifdef LOOSE_OWN_ARRAY_PTR + explicit OwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } + void set(PtrType); +#endif - T* m_ptr; - }; - - template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b) { a.swap(b); } +private: + PtrType m_ptr; +}; + +template<typename T> template<typename U> inline OwnArrayPtr<T>::OwnArrayPtr(const PassOwnArrayPtr<U>& o) + : m_ptr(o.leakPtr()) +{ +} + +template<typename T> inline void OwnArrayPtr<T>::clear() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedArrayPtr(ptr); +} + +template<typename T> inline PassOwnArrayPtr<T> OwnArrayPtr<T>::release() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return adoptArrayPtr(ptr); +} + +template<typename T> inline typename OwnArrayPtr<T>::PtrType OwnArrayPtr<T>::leakPtr() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; +} + +#ifdef LOOSE_OWN_ARRAY_PTR +template<typename T> inline void OwnArrayPtr<T>::set(PtrType ptr) +{ + ASSERT(!ptr || m_ptr != ptr); + PtrType oldPtr = m_ptr; + m_ptr = ptr; + deleteOwnedPtr(oldPtr); +} +#endif - template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p) - { - return p.get(); - } +template<typename T> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& o) +{ + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T> template<typename U> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& o) +{ + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + deleteOwnedArrayPtr(ptr); + return *this; +} + +template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b) +{ + a.swap(b); +} + +template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template<typename T, typename U> inline bool operator==(T* a, const OwnArrayPtr<U>& b) +{ + return a == b.get(); +} + +template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template<typename T, typename U> inline bool operator!=(T* a, const OwnArrayPtr<U>& b) +{ + return a != b.get(); +} + +template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p) +{ + return p.get(); +} } // namespace WTF diff --git a/JavaScriptCore/wtf/OwnArrayPtrCommon.h b/JavaScriptCore/wtf/OwnArrayPtrCommon.h new file mode 100644 index 0000000..0113aff --- /dev/null +++ b/JavaScriptCore/wtf/OwnArrayPtrCommon.h @@ -0,0 +1,40 @@ +/* + * 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. 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 INC. 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 WTF_OwnArrayPtrCommon_h +#define WTF_OwnArrayPtrCommon_h + +namespace WTF { + +template<typename T> inline void deleteOwnedArrayPtr(T* ptr) +{ + typedef char known[sizeof(T) ? 1 : -1]; + if (sizeof(known)) + delete [] ptr; +} + +} // namespace WTF + +#endif // WTF_OwnArrayPtrCommon_h 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..cdc277c 100644 --- a/JavaScriptCore/wtf/OwnPtr.h +++ b/JavaScriptCore/wtf/OwnPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 @@ -23,44 +23,45 @@ #include "Assertions.h" #include "Noncopyable.h" +#include "NullPtr.h" #include "OwnPtrCommon.h" #include "TypeTraits.h" #include <algorithm> #include <memory> +// Remove this once we make all WebKit code compatible with stricter rules about OwnPtr. +#define LOOSE_OWN_PTR + namespace WTF { // Unlike most of our smart pointers, OwnPtr can take either the pointer type or the pointed-to type. - template <typename T> class PassOwnPtr; + template<typename T> class PassOwnPtr; + template<typename T> PassOwnPtr<T> adoptPtr(T*); - template <typename T> class OwnPtr : public Noncopyable { + template<typename T> class OwnPtr : public Noncopyable { public: typedef typename RemovePointer<T>::Type ValueType; typedef ValueType* PtrType; - explicit OwnPtr(PtrType ptr = 0) : m_ptr(ptr) { } - OwnPtr(std::auto_ptr<ValueType> autoPtr) : m_ptr(autoPtr.release()) { } + OwnPtr() : m_ptr(0) { } + // See comment in PassOwnPtr.h for why this takes a const reference. - template <typename U> OwnPtr(const PassOwnPtr<U>& o); + template<typename U> OwnPtr(const PassOwnPtr<U>& o); // This copy constructor is used implicitly by gcc when it generates // transients for assigning a PassOwnPtr<T> object to a stack-allocated - // OwnPtr<T> object. It should never be called explicitly and gcc + // OwnPtr<T> object. It should never be called explicitly and gcc // should optimize away the constructor when generating code. - OwnPtr(const OwnPtr<ValueType>& o); + OwnPtr(const OwnPtr<ValueType>&); ~OwnPtr() { deleteOwnedPtr(m_ptr); } PtrType get() const { return m_ptr; } - PtrType release() { PtrType ptr = m_ptr; m_ptr = 0; return ptr; } - - // 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; } + void clear(); + PassOwnPtr<T> release(); + PtrType leakPtr() WARN_UNUSED_RETURN; ValueType& operator*() const { ASSERT(m_ptr); return *m_ptr; } PtrType operator->() const { ASSERT(m_ptr); return m_ptr; } @@ -72,65 +73,100 @@ namespace WTF { operator UnspecifiedBoolType() const { return m_ptr ? &OwnPtr::m_ptr : 0; } OwnPtr& operator=(const PassOwnPtr<T>&); - template <typename U> OwnPtr& operator=(const PassOwnPtr<U>&); + OwnPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> OwnPtr& operator=(const PassOwnPtr<U>&); void swap(OwnPtr& o) { std::swap(m_ptr, o.m_ptr); } +#ifdef LOOSE_OWN_PTR + explicit OwnPtr(PtrType ptr) : m_ptr(ptr) { } + void set(PtrType); +#endif + private: PtrType m_ptr; }; - template <typename T> template <typename U> inline OwnPtr<T>::OwnPtr(const PassOwnPtr<U>& o) - : m_ptr(o.release()) + template<typename T> template<typename U> inline OwnPtr<T>::OwnPtr(const PassOwnPtr<U>& o) + : m_ptr(o.leakPtr()) + { + } + + template<typename T> inline void OwnPtr<T>::clear() + { + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedPtr(ptr); + } + + template<typename T> inline PassOwnPtr<T> OwnPtr<T>::release() + { + PtrType ptr = m_ptr; + m_ptr = 0; + return adoptPtr(ptr); + } + + template<typename T> inline typename OwnPtr<T>::PtrType OwnPtr<T>::leakPtr() { + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; + } + +#ifdef LOOSE_OWN_PTR + template<typename T> inline void OwnPtr<T>::set(PtrType ptr) + { + ASSERT(!ptr || m_ptr != ptr); + PtrType oldPtr = m_ptr; + m_ptr = ptr; + deleteOwnedPtr(oldPtr); } +#endif - template <typename T> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o) + template<typename T> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o) { - T* ptr = m_ptr; - m_ptr = o.release(); + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); ASSERT(!ptr || m_ptr != ptr); - if (ptr) - deleteOwnedPtr(ptr); + deleteOwnedPtr(ptr); return *this; } - template <typename T> template <typename U> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<U>& o) + template<typename T> template<typename U> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<U>& o) { - T* ptr = m_ptr; - m_ptr = o.release(); + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); ASSERT(!ptr || m_ptr != ptr); - if (ptr) - deleteOwnedPtr(ptr); + deleteOwnedPtr(ptr); return *this; } - template <typename T> inline void swap(OwnPtr<T>& a, OwnPtr<T>& b) + template<typename T> inline void swap(OwnPtr<T>& a, OwnPtr<T>& b) { a.swap(b); } - template <typename T, typename U> inline bool operator==(const OwnPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator==(const OwnPtr<T>& a, U* b) { return a.get() == b; } - template <typename T, typename U> inline bool operator==(T* a, const OwnPtr<U>& b) + template<typename T, typename U> inline bool operator==(T* a, const OwnPtr<U>& b) { return a == b.get(); } - template <typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, U* b) { return a.get() != b; } - template <typename T, typename U> inline bool operator!=(T* a, const OwnPtr<U>& b) + template<typename T, typename U> inline bool operator!=(T* a, const OwnPtr<U>& b) { return a != b.get(); } - template <typename T> inline typename OwnPtr<T>::PtrType getPtr(const OwnPtr<T>& p) + template<typename T> inline typename OwnPtr<T>::PtrType getPtr(const OwnPtr<T>& p) { return p.get(); } diff --git a/JavaScriptCore/wtf/OwnPtrCommon.h b/JavaScriptCore/wtf/OwnPtrCommon.h index 6d91a54..19256ea 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,18 @@ 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 _ISocket ISocket; +typedef struct _IFileMgr IFileMgr; +typedef struct _IFile IFile; +typedef struct IBitmap IBitmap; +typedef struct ISSL ISSL; +typedef struct IMemGroup IMemGroup; +typedef struct IMemSpace IMemSpace; +#endif + namespace WTF { template <typename T> inline void deleteOwnedPtr(T* ptr) @@ -56,6 +69,16 @@ namespace WTF { void deleteOwnedPtr(HRGN); #endif +#if PLATFORM(BREWMP) + void deleteOwnedPtr(IFileMgr*); + void deleteOwnedPtr(IFile*); + void deleteOwnedPtr(IBitmap*); + void deleteOwnedPtr(ISSL*); + void deleteOwnedPtr(ISocket*); + void deleteOwnedPtr(IMemGroup*); + void deleteOwnedPtr(IMemSpace*); +#endif + } // namespace WTF #endif // WTF_OwnPtrCommon_h diff --git a/JavaScriptCore/wtf/PageAllocation.cpp b/JavaScriptCore/wtf/PageAllocation.cpp new file mode 100644 index 0000000..f3fe997 --- /dev/null +++ b/JavaScriptCore/wtf/PageAllocation.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageAllocation.h" +#include "PageReservation.h" + +namespace WTF { + +size_t PageAllocation::s_pageSize = 0; + +#ifndef NDEBUG + +int PageAllocation::lastError() +{ +#if OS(WINCE) + return GetLastError(); +#else + return errno; +#endif +} + +#endif + +} diff --git a/JavaScriptCore/wtf/PageAllocation.h b/JavaScriptCore/wtf/PageAllocation.h new file mode 100644 index 0000000..26d53a5 --- /dev/null +++ b/JavaScriptCore/wtf/PageAllocation.h @@ -0,0 +1,361 @@ +/* + * 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 PageAllocation_h +#define PageAllocation_h + +#include <wtf/Assertions.h> +#include <wtf/UnusedParam.h> +#include <wtf/VMTags.h> + +#if OS(DARWIN) +#include <mach/mach_init.h> +#include <mach/vm_map.h> +#endif + +#if OS(HAIKU) +#include <OS.h> +#endif + +#if OS(WINDOWS) +#include <malloc.h> +#include <windows.h> +#endif + +#if OS(SYMBIAN) +#include <e32hal.h> +#include <e32std.h> +#endif + +#if HAVE(ERRNO_H) +#include <errno.h> +#endif + +#if HAVE(MMAP) +#include <sys/mman.h> +#include <unistd.h> +#endif + +namespace WTF { + +/* + PageAllocation + + The PageAllocation class provides a cross-platform memory allocation interface + with similar capabilities to posix mmap/munmap. Memory is allocated by calling + PageAllocation::allocate, and deallocated by calling deallocate on the + PageAllocation object. The PageAllocation holds the allocation's base pointer + and size. + + The allocate method is passed the size required (which must be a multiple of + the system page size, which can be accessed using PageAllocation::pageSize). + Callers may also optinally provide a flag indicating the usage (for use by + system memory usage tracking tools, where implemented), and boolean values + specifying the required protection (defaulting to writable, non-executable). + + Where HAVE(PAGE_ALLOCATE_AT) and HAVE(PAGE_ALLOCATE_ALIGNED) are available + memory may also be allocated at a specified address, or with a specified + alignment respectively. PageAllocation::allocateAt take an address to try + to allocate at, and a boolean indicating whether this behaviour is strictly + required (if this address is unavailable, should memory at another address + be allocated instead). PageAllocation::allocateAligned requires that the + size is a power of two that is >= system page size. +*/ +class PageAllocation { +public: + enum Usage { + UnknownUsage = -1, + FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY, + JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY, + JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY, + JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, + }; + + PageAllocation() + : m_base(0) + , m_size(0) +#if OS(SYMBIAN) + , m_chunk(0) +#endif + { + } + + bool operator!() const { return !m_base; } + void* base() const { return m_base; } + size_t size() const { return m_size; } + + static PageAllocation allocate(size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(size)); + return systemAllocate(size, usage, writable, executable); + } + +#if HAVE(PAGE_ALLOCATE_AT) + static PageAllocation allocateAt(void* address, bool fixed, size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(address)); + ASSERT(isPageAligned(size)); + return systemAllocateAt(address, fixed, size, usage, writable, executable); + } +#endif + +#if HAVE(PAGE_ALLOCATE_ALIGNED) + static PageAllocation allocateAligned(size_t size, Usage usage = UnknownUsage) + { + ASSERT(isPageAligned(size)); + ASSERT(isPowerOfTwo(size)); + return systemAllocateAligned(size, usage); + } +#endif + + void deallocate() + { + ASSERT(m_base); + systemDeallocate(true); + } + + static size_t pageSize() + { + if (!s_pageSize) + s_pageSize = systemPageSize(); + ASSERT(isPowerOfTwo(s_pageSize)); + return s_pageSize; + } + +#ifndef NDEBUG + static bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); } + static bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); } + static bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); } + static int lastError(); +#endif + +protected: +#if OS(SYMBIAN) + PageAllocation(void* base, size_t size, RChunk* chunk) + : m_base(base) + , m_size(size) + , m_chunk(chunk) + { + } +#else + PageAllocation(void* base, size_t size) + : m_base(base) + , m_size(size) + { + } +#endif + + static PageAllocation systemAllocate(size_t, Usage, bool, bool); +#if HAVE(PAGE_ALLOCATE_AT) + static PageAllocation systemAllocateAt(void*, bool, size_t, Usage, bool, bool); +#endif +#if HAVE(PAGE_ALLOCATE_ALIGNED) + static PageAllocation systemAllocateAligned(size_t, Usage); +#endif + // systemDeallocate takes a parameter indicating whether memory is currently committed + // (this should always be true for PageAllocation, false for PageReservation). + void systemDeallocate(bool committed); + static size_t systemPageSize(); + + void* m_base; + size_t m_size; +#if OS(SYMBIAN) + RChunk* m_chunk; +#endif + + static JS_EXPORTDATA size_t s_pageSize; +}; + + +#if HAVE(MMAP) + + +inline PageAllocation PageAllocation::systemAllocate(size_t size, Usage usage, bool writable, bool executable) +{ + return systemAllocateAt(0, false, size, usage, writable, executable); +} + +inline PageAllocation PageAllocation::systemAllocateAt(void* address, bool fixed, size_t size, Usage usage, bool writable, bool executable) +{ + int protection = PROT_READ; + if (writable) + protection |= PROT_WRITE; + if (executable) + protection |= PROT_EXEC; + + int flags = MAP_PRIVATE | MAP_ANON; + if (fixed) + flags |= MAP_FIXED; + +#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) + int fd = usage; +#else + int fd = -1; +#endif + + void* base = mmap(address, size, protection, flags, fd, 0); + if (base == MAP_FAILED) + base = 0; + return PageAllocation(base, size); +} + +inline PageAllocation PageAllocation::systemAllocateAligned(size_t size, Usage usage) +{ +#if OS(DARWIN) + vm_address_t address = 0; + int flags = VM_FLAGS_ANYWHERE; + if (usage != -1) + flags |= usage; + vm_map(current_task(), &address, size, (size - 1), flags, MEMORY_OBJECT_NULL, 0, FALSE, PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE | PROT_EXEC, VM_INHERIT_DEFAULT); + return PageAllocation(reinterpret_cast<void*>(address), size); +#elif HAVE(POSIX_MEMALIGN) + void* address; + posix_memalign(&address, size, size); + return PageAllocation(address, size); +#else + size_t extra = size - pageSize(); + + // Check for overflow. + if ((size + extra) < size) + return PageAllocation(0, size); + +#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) + int fd = usage; +#else + int fd = -1; +#endif + void* mmapResult = mmap(0, size + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, fd, 0); + if (mmapResult == MAP_FAILED) + return PageAllocation(0, size); + uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult); + + size_t adjust = 0; + if ((address & (size - 1))) + adjust = size - (address & (size - 1)); + if (adjust > 0) + munmap(reinterpret_cast<char*>(address), adjust); + if (adjust < extra) + munmap(reinterpret_cast<char*>(address + adjust + size), extra - adjust); + address += adjust; + + return PageAllocation(reinterpret_cast<void*>(address), size); +#endif +} + +inline void PageAllocation::systemDeallocate(bool) +{ + int result = munmap(m_base, m_size); + ASSERT_UNUSED(result, !result); + m_base = 0; +} + +inline size_t PageAllocation::systemPageSize() +{ + return getpagesize(); +} + + +#elif HAVE(VIRTUALALLOC) + + +inline PageAllocation PageAllocation::systemAllocate(size_t size, Usage, bool writable, bool executable) +{ + DWORD protection = executable ? + (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) : + (writable ? PAGE_READWRITE : PAGE_READONLY); + return PageAllocation(VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, protection), size); +} + +#if HAVE(ALIGNED_MALLOC) +inline PageAllocation PageAllocation::systemAllocateAligned(size_t size, Usage usage) +{ +#if COMPILER(MINGW) && !COMPILER(MINGW64) + void* address = __mingw_aligned_malloc(size, size); +#else + void* address = _aligned_malloc(size, size); +#endif + memset(address, 0, size); + return PageAllocation(address, size); +} +#endif + +inline void PageAllocation::systemDeallocate(bool committed) +{ +#if OS(WINCE) + if (committed) + VirtualFree(m_base, m_size, MEM_DECOMMIT); +#else + UNUSED_PARAM(committed); +#endif + VirtualFree(m_base, 0, MEM_RELEASE); + m_base = 0; +} + +inline size_t PageAllocation::systemPageSize() +{ + static size_t size = 0; + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + size = system_info.dwPageSize; + return size; +} + + +#elif OS(SYMBIAN) + + +inline PageAllocation PageAllocation::systemAllocate(size_t size, Usage usage, bool writable, bool executable) +{ + RChunk* rchunk = new RChunk(); + if (executable) + rchunk->CreateLocalCode(size, size); + else + rchunk->CreateLocal(size, size); + return PageAllocation(rchunk->Base(), size, rchunk); +} + +inline void PageAllocation::systemDeallocate(bool) +{ + m_chunk->Close(); + delete m_chunk; + m_base = 0; +} + +inline size_t PageAllocation::systemPageSize() +{ + static TInt page_size = 0; + UserHal::PageSizeInBytes(page_size); + return page_size; +} + + +#endif + + +} + +using WTF::PageAllocation; + +#endif // PageAllocation_h diff --git a/JavaScriptCore/wtf/PageReservation.h b/JavaScriptCore/wtf/PageReservation.h new file mode 100644 index 0000000..cfc7cd9 --- /dev/null +++ b/JavaScriptCore/wtf/PageReservation.h @@ -0,0 +1,258 @@ +/* + * 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 PageReservation_h +#define PageReservation_h + +#include <wtf/PageAllocation.h> + +namespace WTF { + +/* + PageReservation + + Like PageAllocation, the PageReservation class provides a cross-platform memory + allocation interface, but with a set of capabilities more similar to that of + VirtualAlloc than posix mmap. PageReservation can be used to allocate virtual + memory without committing physical memory pages using PageReservation::reserve. + Following a call to reserve all memory in the region is in a decommited state, + in which the memory should not be used (accessing the memory may cause a fault). + + Before using memory it must be committed by calling commit, which is passed start + and size values (both of which require system page size granularity). One the + committed memory is no longer needed 'decommit' may be called to return the + memory to its devommitted state. Commit should only be called on memory that is + currently decommitted, and decommit should only be called on memory regions that + are currently committed. All memory should be decommited before the reservation + is deallocated. Values in memory may not be retained accross a pair of calls if + the region of memory is decommitted and then committed again. + + Where HAVE(PAGE_ALLOCATE_AT) is available a PageReservation::reserveAt method + also exists, with behaviour mirroring PageAllocation::allocateAt. + + Memory protection should not be changed on decommitted memory, and if protection + is changed on memory while it is committed it should be returned to the orignal + protection before decommit is called. + + Note: Inherits from PageAllocation privately to prevent clients accidentally + calling PageAllocation::deallocate on a PageReservation. +*/ +class PageReservation : private PageAllocation { +public: + PageReservation() + { + } + + using PageAllocation::operator!; + using PageAllocation::base; + using PageAllocation::size; + + bool commit(void* start, size_t size) + { + ASSERT(m_base); + ASSERT(isPageAligned(start)); + ASSERT(isPageAligned(size)); + + bool commited = systemCommit(start, size); +#ifndef NDEBUG + if (commited) + m_committed += size; +#endif + return commited; + } + void decommit(void* start, size_t size) + { + ASSERT(m_base); + ASSERT(isPageAligned(start)); + ASSERT(isPageAligned(size)); + +#ifndef NDEBUG + m_committed -= size; +#endif + systemDecommit(start, size); + } + + static PageReservation reserve(size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(size)); + return systemReserve(size, usage, writable, executable); + } + +#if HAVE(PAGE_ALLOCATE_AT) + static PageReservation reserveAt(void* address, bool fixed, size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(address)); + ASSERT(isPageAligned(size)); + return systemReserveAt(address, fixed, size, usage, writable, executable); + } +#endif + + void deallocate() + { + ASSERT(m_base); + ASSERT(!m_committed); + systemDeallocate(false); + } + +#ifndef NDEBUG + using PageAllocation::lastError; +#endif + +private: +#if OS(SYMBIAN) + PageReservation(void* base, size_t size, RChunk* chunk) + : PageAllocation(base, size, chunk) +#else + PageReservation(void* base, size_t size) + : PageAllocation(base, size) +#endif +#ifndef NDEBUG + , m_committed(0) +#endif + { + } + + bool systemCommit(void*, size_t); + void systemDecommit(void*, size_t); + static PageReservation systemReserve(size_t, Usage, bool, bool); +#if HAVE(PAGE_ALLOCATE_AT) + static PageReservation systemReserveAt(void*, bool, size_t, Usage, bool, bool); +#endif + +#if HAVE(VIRTUALALLOC) + DWORD m_protection; +#endif +#ifndef NDEBUG + size_t m_committed; +#endif +}; + + +#if HAVE(MMAP) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ +#if HAVE(MADV_FREE_REUSE) + while (madvise(start, size, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } +#else + UNUSED_PARAM(start); + UNUSED_PARAM(size); +#endif + return true; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ +#if HAVE(MADV_FREE_REUSE) + while (madvise(start, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#elif HAVE(MADV_FREE) + while (madvise(start, size, MADV_FREE) == -1 && errno == EAGAIN) { } +#elif HAVE(MADV_DONTNEED) + while (madvise(start, size, MADV_DONTNEED) == -1 && errno == EAGAIN) { } +#else + UNUSED_PARAM(start); + UNUSED_PARAM(size); +#endif +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + return systemReserveAt(0, false, size, usage, writable, executable); +} + +inline PageReservation PageReservation::systemReserveAt(void* address, bool fixed, size_t size, Usage usage, bool writable, bool executable) +{ + void* base = systemAllocateAt(address, fixed, size, usage, writable, executable).base(); +#if HAVE(MADV_FREE_REUSE) + // When using MADV_FREE_REUSE we keep all decommitted memory marked as REUSABLE. + // We call REUSE on commit, and REUSABLE on decommit. + if (base) + while (madvise(base, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#endif + return PageReservation(base, size); +} + + +#elif HAVE(VIRTUALALLOC) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ + return VirtualAlloc(start, size, MEM_COMMIT, m_protection) == start; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ + VirtualFree(start, size, MEM_DECOMMIT); +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + // Record the protection for use during commit. + DWORD protection = executable ? + (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) : + (writable ? PAGE_READWRITE : PAGE_READONLY); + PageReservation reservation(VirtualAlloc(0, size, MEM_RESERVE, protection), size); + reservation.m_protection = protection; + return reservation; +} + + +#elif OS(SYMBIAN) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ + intptr_t offset = reinterpret_cast<intptr_t>(start) - reinterpret_cast<intptr_t>(m_base); + m_chunk->Commit(offset, size); + return true; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ + intptr_t offset = reinterpret_cast<intptr_t>(start) - reinterpret_cast<intptr_t>(m_base); + m_chunk->Decommit(offset, size); +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + RChunk* rchunk = new RChunk(); + if (executable) + rchunk->CreateLocalCode(0, size); + else + rchunk->CreateDisconnectedLocal(0, 0, size); + return PageReservation(rchunk->Base(), size, rchunk); +} + + +#endif + + +} + +using WTF::PageReservation; + +#endif // PageReservation_h diff --git a/JavaScriptCore/wtf/PassOwnArrayPtr.h b/JavaScriptCore/wtf/PassOwnArrayPtr.h new file mode 100644 index 0000000..6a55491 --- /dev/null +++ b/JavaScriptCore/wtf/PassOwnArrayPtr.h @@ -0,0 +1,217 @@ +/* + * 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 WTF_PassOwnArrayPtr_h +#define WTF_PassOwnArrayPtr_h + +#include "Assertions.h" +#include "NullPtr.h" +#include "OwnArrayPtrCommon.h" +#include "TypeTraits.h" + +// Remove this once we make all WebKit code compatible with stricter rules about PassOwnArrayPtr. +#define LOOSE_PASS_OWN_ARRAY_PTR + +namespace WTF { + +template<typename T> class OwnArrayPtr; +template<typename T> class PassOwnArrayPtr; +template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*); + +template<typename T> class PassOwnArrayPtr { +public: + typedef T* PtrType; + + PassOwnArrayPtr() : m_ptr(0) { } + + // It somewhat breaks the type system to allow transfer of ownership out of + // a const PassOwnArrayPtr. However, it makes it much easier to work with PassOwnArrayPtr + // temporaries, and we don't have a need to use real const PassOwnArrayPtrs anyway. + PassOwnArrayPtr(const PassOwnArrayPtr& o) : m_ptr(o.leakPtr()) { } + template<typename U> PassOwnArrayPtr(const PassOwnArrayPtr<U>& o) : m_ptr(o.leakPtr()) { } + + ~PassOwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); } + + PtrType get() const { return m_ptr; } + + void clear(); + PtrType leakPtr() const WARN_UNUSED_RETURN; + + T& operator*() const { ASSERT(m_ptr); return *m_ptr; } + PtrType 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. +#if COMPILER(WINSCW) + operator bool() const { return m_ptr; } +#else + typedef PtrType PassOwnArrayPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnArrayPtr::m_ptr : 0; } +#endif + + PassOwnArrayPtr& operator=(const PassOwnArrayPtr<T>&); + PassOwnArrayPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> PassOwnArrayPtr& operator=(const PassOwnArrayPtr<U>&); + + template<typename U> friend PassOwnArrayPtr<U> adoptArrayPtr(U*); + +#ifdef LOOSE_PASS_OWN_ARRAY_PTR + PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } + PassOwnArrayPtr& operator=(PtrType); +#endif + +private: +#ifndef LOOSE_PASS_OWN_ARRAY_PTR + explicit PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } +#endif + + mutable PtrType m_ptr; +}; + +template<typename T> inline void PassOwnArrayPtr<T>::clear() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedArrayPtr(ptr); +} + +template<typename T> inline typename PassOwnArrayPtr<T>::PtrType PassOwnArrayPtr<T>::leakPtr() const +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; +} + +#ifdef LOOSE_PASS_OWN_ARRAY_PTR +template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(PtrType optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr; + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} +#endif + +template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T> template<typename U> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template<typename T, typename U> inline bool operator==(T* a, const PassOwnArrayPtr<U>& b) +{ + return a == b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template<typename T, typename U> inline bool operator!=(T* a, const PassOwnArrayPtr<U>& b) +{ + return a != b.get(); +} + +template<typename T> inline PassOwnArrayPtr<T> adoptArrayPtr(T* ptr) +{ + return PassOwnArrayPtr<T>(ptr); +} + +template<typename T, typename U> inline PassOwnArrayPtr<T> static_pointer_cast(const PassOwnArrayPtr<U>& p) +{ + return adoptArrayPtr(static_cast<T*>(p.leakPtr())); +} + +template<typename T, typename U> inline PassOwnArrayPtr<T> const_pointer_cast(const PassOwnArrayPtr<U>& p) +{ + return adoptArrayPtr(const_cast<T*>(p.leakPtr())); +} + +template<typename T> inline T* getPtr(const PassOwnArrayPtr<T>& p) +{ + return p.get(); +} + +} // namespace WTF + +using WTF::PassOwnArrayPtr; +using WTF::adoptArrayPtr; +using WTF::const_pointer_cast; +using WTF::static_pointer_cast; + +#endif // WTF_PassOwnArrayPtr_h diff --git a/JavaScriptCore/wtf/PassOwnPtr.h b/JavaScriptCore/wtf/PassOwnPtr.h index ae70457..60453fc 100644 --- a/JavaScriptCore/wtf/PassOwnPtr.h +++ b/JavaScriptCore/wtf/PassOwnPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -27,34 +27,40 @@ #define WTF_PassOwnPtr_h #include "Assertions.h" +#include "NullPtr.h" #include "OwnPtrCommon.h" #include "TypeTraits.h" +// Remove this once we make all WebKit code compatible with stricter rules about PassOwnPtr. +#define LOOSE_PASS_OWN_PTR + namespace WTF { // Unlike most of our smart pointers, PassOwnPtr can take either the pointer type or the pointed-to type. - template <typename T> class OwnPtr; + template<typename T> class OwnPtr; + template<typename T> class PassOwnPtr; + template<typename T> PassOwnPtr<T> adoptPtr(T*); - template <typename T> class PassOwnPtr { + template<typename T> class PassOwnPtr { public: typedef typename RemovePointer<T>::Type ValueType; typedef ValueType* PtrType; - PassOwnPtr(PtrType ptr = 0) : m_ptr(ptr) { } + PassOwnPtr() : m_ptr(0) { } + // It somewhat breaks the type system to allow transfer of ownership out of // a const PassOwnPtr. However, it makes it much easier to work with PassOwnPtr - // temporaries, and we don't really have a need to use real const PassOwnPtrs - // anyway. - PassOwnPtr(const PassOwnPtr& o) : m_ptr(o.release()) { } - template <typename U> PassOwnPtr(const PassOwnPtr<U>& o) : m_ptr(o.release()) { } + // temporaries, and we don't have a need to use real const PassOwnPtrs anyway. + PassOwnPtr(const PassOwnPtr& o) : m_ptr(o.leakPtr()) { } + template<typename U> PassOwnPtr(const PassOwnPtr<U>& o) : m_ptr(o.leakPtr()) { } ~PassOwnPtr() { deleteOwnedPtr(m_ptr); } PtrType get() const { return m_ptr; } - void clear() { m_ptr = 0; } - PtrType release() const { PtrType ptr = m_ptr; m_ptr = 0; return ptr; } + void clear(); + PtrType leakPtr() const WARN_UNUSED_RETURN; ValueType& operator*() const { ASSERT(m_ptr); return *m_ptr; } PtrType operator->() const { ASSERT(m_ptr); return m_ptr; } @@ -65,105 +71,137 @@ namespace WTF { typedef PtrType PassOwnPtr::*UnspecifiedBoolType; operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnPtr::m_ptr : 0; } - PassOwnPtr& operator=(T*); PassOwnPtr& operator=(const PassOwnPtr<T>&); - template <typename U> PassOwnPtr& operator=(const PassOwnPtr<U>&); + PassOwnPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> PassOwnPtr& operator=(const PassOwnPtr<U>&); + + template<typename U> friend PassOwnPtr<U> adoptPtr(U*); + +#ifdef LOOSE_PASS_OWN_PTR + PassOwnPtr(PtrType ptr) : m_ptr(ptr) { } + PassOwnPtr& operator=(PtrType); +#endif private: +#ifndef LOOSE_PASS_OWN_PTR + explicit PassOwnPtr(PtrType ptr) : m_ptr(ptr) { } +#endif + mutable PtrType m_ptr; }; - template <typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(T* optr) + template<typename T> inline void PassOwnPtr<T>::clear() + { + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedPtr(ptr); + } + + template<typename T> inline typename PassOwnPtr<T>::PtrType PassOwnPtr<T>::leakPtr() const + { + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; + } + +#ifdef LOOSE_PASS_OWN_PTR + template<typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(PtrType optr) { - T* ptr = m_ptr; + PtrType ptr = m_ptr; m_ptr = optr; ASSERT(!ptr || m_ptr != ptr); if (ptr) deleteOwnedPtr(ptr); return *this; } +#endif - template <typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<T>& optr) + template<typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<T>& optr) { - T* ptr = m_ptr; - m_ptr = optr.release(); + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); ASSERT(!ptr || m_ptr != ptr); if (ptr) deleteOwnedPtr(ptr); return *this; } - template <typename T> template <typename U> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<U>& optr) + template<typename T> template<typename U> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<U>& optr) { - T* ptr = m_ptr; - m_ptr = optr.release(); + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); ASSERT(!ptr || m_ptr != ptr); if (ptr) deleteOwnedPtr(ptr); return *this; } - template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const OwnPtr<U>& b) + template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const OwnPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const OwnPtr<T>& a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator==(const OwnPtr<T>& a, const PassOwnPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, U* b) { return a.get() == b; } - template <typename T, typename U> inline bool operator==(T* a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator==(T* a, const PassOwnPtr<U>& b) { return a == b.get(); } - template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const OwnPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const OwnPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, const PassOwnPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, U* b) { return a.get() != b; } - template <typename T, typename U> inline bool operator!=(T* a, const PassOwnPtr<U>& b) + template<typename T, typename U> inline bool operator!=(T* a, const PassOwnPtr<U>& b) { return a != b.get(); } - template <typename T, typename U> inline PassOwnPtr<T> static_pointer_cast(const PassOwnPtr<U>& p) + template<typename T> inline PassOwnPtr<T> adoptPtr(T* ptr) + { + return PassOwnPtr<T>(ptr); + } + + template<typename T, typename U> inline PassOwnPtr<T> static_pointer_cast(const PassOwnPtr<U>& p) { - return PassOwnPtr<T>(static_cast<T*>(p.release())); + return adoptPtr(static_cast<T*>(p.leakPtr())); } - template <typename T, typename U> inline PassOwnPtr<T> const_pointer_cast(const PassOwnPtr<U>& p) + template<typename T, typename U> inline PassOwnPtr<T> const_pointer_cast(const PassOwnPtr<U>& p) { - return PassOwnPtr<T>(const_cast<T*>(p.release())); + return adoptPtr(const_cast<T*>(p.leakPtr())); } - template <typename T> inline T* getPtr(const PassOwnPtr<T>& p) + template<typename T> inline T* getPtr(const PassOwnPtr<T>& p) { return p.get(); } @@ -171,6 +209,7 @@ namespace WTF { } // namespace WTF using WTF::PassOwnPtr; +using WTF::adoptPtr; using WTF::const_pointer_cast; using WTF::static_pointer_cast; diff --git a/JavaScriptCore/wtf/PassRefPtr.h b/JavaScriptCore/wtf/PassRefPtr.h index 9c6e44f..b179cef 100644 --- a/JavaScriptCore/wtf/PassRefPtr.h +++ b/JavaScriptCore/wtf/PassRefPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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 @@ -22,61 +22,67 @@ #define WTF_PassRefPtr_h #include "AlwaysInline.h" +#include "NullPtr.h" namespace WTF { template<typename T> class RefPtr; template<typename T> class PassRefPtr; - template <typename T> PassRefPtr<T> adoptRef(T*); + template<typename T> PassRefPtr<T> adoptRef(T*); + inline void adopted(const void*) { } - // Remove inline for WINSCW compiler to prevent the compiler agressively resolving +#if !COMPILER(WINSCW) +#if !PLATFORM(QT) + #define REF_DEREF_INLINE ALWAYS_INLINE +#else + // Using ALWAYS_INLINE broke the Qt build. This may be a GCC bug. + // See https://bugs.webkit.org/show_bug.cgi?id=37253 for details. + #define REF_DEREF_INLINE inline +#endif +#else + // No inlining 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. - template<typename T> -#if !COMPILER(WINSCW) - inline + #define REF_DEREF_INLINE #endif - void refIfNotNull(T* ptr) + + template<typename T> REF_DEREF_INLINE void refIfNotNull(T* ptr) { - if (UNLIKELY(ptr != 0)) + if (LIKELY(ptr != 0)) ptr->ref(); } - template<typename T> -#if !COMPILER(WINSCW) - inline -#endif - void derefIfNotNull(T* ptr) + template<typename T> REF_DEREF_INLINE void derefIfNotNull(T* ptr) { - if (UNLIKELY(ptr != 0)) + if (LIKELY(ptr != 0)) ptr->deref(); } + #undef REF_DEREF_INLINE + template<typename T> class PassRefPtr { public: - PassRefPtr() : m_ptr(0) {} + PassRefPtr() : m_ptr(0) { } PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); } // It somewhat breaks the type system to allow transfer of ownership out of // a const PassRefPtr. However, it makes it much easier to work with PassRefPtr - // temporaries, and we don't really have a need to use real const PassRefPtrs - // anyway. - PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef()) {} - template <typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.releaseRef()) { } + // temporaries, and we don't have a need to use real const PassRefPtrs anyway. + PassRefPtr(const PassRefPtr& o) : m_ptr(o.leakRef()) { } + template<typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.leakRef()) { } ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull(m_ptr); } - template <class U> - PassRefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { T* ptr = m_ptr; refIfNotNull(ptr); } + template<typename U> PassRefPtr(const RefPtr<U>&); T* get() const { return m_ptr; } - void clear() { T* ptr = m_ptr; derefIfNotNull(ptr); m_ptr = 0; } - T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; } + void clear(); + T* leakRef() const WARN_UNUSED_RETURN; T& operator*() const { return *m_ptr; } T* operator->() const { return m_ptr; } - + bool operator!() const { return !m_ptr; } // This conversion operator allows implicit conversion to bool but not to other integer types. @@ -85,25 +91,31 @@ namespace WTF { PassRefPtr& operator=(T*); PassRefPtr& operator=(const PassRefPtr&); - template <typename U> PassRefPtr& operator=(const PassRefPtr<U>&); - template <typename U> PassRefPtr& operator=(const RefPtr<U>&); + PassRefPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> PassRefPtr& operator=(const PassRefPtr<U>&); + template<typename U> PassRefPtr& operator=(const RefPtr<U>&); friend PassRefPtr adoptRef<T>(T*); + + // FIXME: Remove releaseRef once we change all callers to call leakRef instead. + T* releaseRef() const WARN_UNUSED_RETURN { return leakRef(); } + private: // adopting constructor - PassRefPtr(T* ptr, bool) : m_ptr(ptr) {} + PassRefPtr(T* ptr, bool) : m_ptr(ptr) { } + mutable T* m_ptr; }; // NonNullPassRefPtr: Optimized for passing non-null pointers. A NonNullPassRefPtr - // begins life non-null, and can only become null through a call to releaseRef() + // begins life non-null, and can only become null through a call to leakRef() // or clear(). // FIXME: NonNullPassRefPtr could just inherit from PassRefPtr. However, // if we use inheritance, GCC's optimizer fails to realize that destruction // of a released NonNullPassRefPtr is a no-op. So, for now, just copy the // most important code from PassRefPtr. - template <typename T> class NonNullPassRefPtr { + template<typename T> class NonNullPassRefPtr { public: NonNullPassRefPtr(T* ptr) : m_ptr(ptr) @@ -112,7 +124,7 @@ namespace WTF { m_ptr->ref(); } - template <class U> NonNullPassRefPtr(const RefPtr<U>& o) + template<typename U> NonNullPassRefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { ASSERT(m_ptr); @@ -120,19 +132,19 @@ namespace WTF { } NonNullPassRefPtr(const NonNullPassRefPtr& o) - : m_ptr(o.releaseRef()) + : m_ptr(o.leakRef()) { ASSERT(m_ptr); } - template <class U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o) - : m_ptr(o.releaseRef()) + template<typename U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o) + : m_ptr(o.leakRef()) { ASSERT(m_ptr); } - template <class U> NonNullPassRefPtr(const PassRefPtr<U>& o) - : m_ptr(o.releaseRef()) + template<typename U> NonNullPassRefPtr(const PassRefPtr<U>& o) + : m_ptr(o.leakRef()) { ASSERT(m_ptr); } @@ -141,17 +153,41 @@ namespace WTF { T* get() const { return m_ptr; } - void clear() { derefIfNotNull(m_ptr); m_ptr = 0; } - T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; } + void clear(); + T* leakRef() const WARN_UNUSED_RETURN { T* tmp = m_ptr; m_ptr = 0; return tmp; } T& operator*() const { return *m_ptr; } T* operator->() const { return m_ptr; } + // FIXME: Remove releaseRef once we change all callers to call leakRef instead. + T* releaseRef() const WARN_UNUSED_RETURN { return leakRef(); } + private: mutable T* m_ptr; }; - template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o) + template<typename T> template<typename U> inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o) + : m_ptr(o.get()) + { + T* ptr = m_ptr; + refIfNotNull(ptr); + } + + template<typename T> inline void PassRefPtr<T>::clear() + { + T* ptr = m_ptr; + m_ptr = 0; + derefIfNotNull(ptr); + } + + template<typename T> inline T* PassRefPtr<T>::leakRef() const + { + T* ptr = m_ptr; + m_ptr = 0; + return ptr; + } + + template<typename T> template<typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o) { T* optr = o.get(); refIfNotNull(optr); @@ -161,7 +197,7 @@ namespace WTF { return *this; } - template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr) + template<typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr) { refIfNotNull(optr); T* ptr = m_ptr; @@ -170,92 +206,100 @@ namespace WTF { return *this; } - template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref) + template<typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref) { T* ptr = m_ptr; - m_ptr = ref.releaseRef(); + m_ptr = ref.leakRef(); derefIfNotNull(ptr); return *this; } - template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<U>& ref) + template<typename T> template<typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<U>& ref) { T* ptr = m_ptr; - m_ptr = ref.releaseRef(); + m_ptr = ref.leakRef(); derefIfNotNull(ptr); return *this; } - template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, U* b) { return a.get() == b; } - template <typename T, typename U> inline bool operator==(T* a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator==(T* a, const PassRefPtr<U>& b) { return a == b.get(); } - template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, U* b) { return a.get() != b; } - template <typename T, typename U> inline bool operator!=(T* a, const PassRefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(T* a, const PassRefPtr<U>& b) { return a != b.get(); } - template <typename T> inline PassRefPtr<T> adoptRef(T* p) + template<typename T> inline PassRefPtr<T> adoptRef(T* p) { + adopted(p); return PassRefPtr<T>(p, true); } - template <typename T, typename U> inline PassRefPtr<T> static_pointer_cast(const PassRefPtr<U>& p) + template<typename T, typename U> inline PassRefPtr<T> static_pointer_cast(const PassRefPtr<U>& p) { - return adoptRef(static_cast<T*>(p.releaseRef())); + return adoptRef(static_cast<T*>(p.leakRef())); } - template <typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p) + template<typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p) { - return adoptRef(const_cast<T*>(p.releaseRef())); + return adoptRef(const_cast<T*>(p.leakRef())); } - template <typename T> inline T* getPtr(const PassRefPtr<T>& p) + template<typename T> inline T* getPtr(const PassRefPtr<T>& p) { return p.get(); } + template<typename T> inline void NonNullPassRefPtr<T>::clear() + { + T* ptr = m_ptr; + m_ptr = 0; + derefIfNotNull(ptr); + } + } // namespace WTF using WTF::PassRefPtr; diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index a6ded58..221cda6 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,11 +59,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 @@ -76,19 +80,34 @@ #if defined(__GNUC__) && !COMPILER(RVCT) #define WTF_COMPILER_GCC 1 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch)) +#else +/* define this for !GCC compilers, just so we can write things like COMPILER(GCC) && GCC_VERSION_AT_LEAST(4,1,0) */ +#define GCC_VERSION_AT_LEAST(major, minor, patch) 0 #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 - +/* COMPILER(INTEL) - Intel C++ Compiler */ +#if defined(__INTEL_COMPILER) +#define WTF_COMPILER_INTEL 1 +#endif /* ==== CPU() - the target CPU architecture ==== */ @@ -102,7 +121,31 @@ /* 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) +#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64) +/* MIPS requires allocators to use aligned memory */ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 +#endif /* MIPS */ /* CPU(PPC) - PowerPC 32-bit */ #if defined(__ppc__) \ @@ -142,7 +185,19 @@ /* 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(S390X) - S390 64-bit */ +#if defined(__s390x__) +#define WTF_CPU_S390X 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(S390) - S390 32-bit */ +#if defined(__s390__) +#define WTF_CPU_S390 1 +#define WTF_CPU_BIG_ENDIAN 1 #endif /* CPU(X86) - i386 / x86 32-bit */ @@ -162,15 +217,18 @@ /* CPU(ARM) - ARM, any version*/ #if defined(arm) \ - || defined(__arm__) + || defined(__arm__) \ + || defined(ARM) \ + || defined(_ARM_) #define WTF_CPU_ARM 1 -#if defined(__ARMEB__) +#if defined(__ARMEB__) || (COMPILER(RVCT) && defined(__BIG_ENDIAN)) #define WTF_CPU_BIG_ENDIAN 1 #elif !defined(__ARM_EABI__) \ && !defined(__EABI__) \ && !defined(__VFP_FP__) \ + && !defined(_WIN32_WCE) \ && !defined(ANDROID) #define WTF_CPU_MIDDLE_ENDIAN 1 @@ -187,12 +245,16 @@ #elif defined(__ARM_ARCH_5__) \ || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5E__) \ - || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) \ || defined(__MARM_ARMV5__) #define WTF_ARM_ARCH_VERSION 5 +#elif defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +#define WTF_ARM_ARCH_VERSION 5 +/*ARMv5TE requires allocators to use aligned memory*/ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 + #elif defined(__ARM_ARCH_6__) \ || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) \ @@ -210,6 +272,13 @@ #elif defined(__TARGET_ARCH_ARM) #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM +#if defined(__TARGET_ARCH_5E) \ + || defined(__TARGET_ARCH_5TE) \ + || defined(__TARGET_ARCH_5TEJ) +/*ARMv5TE requires allocators to use aligned memory*/ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 +#endif + #else #define WTF_ARM_ARCH_VERSION 0 @@ -314,12 +383,12 @@ #endif -/* OS(IPHONE_OS) - iPhone OS */ -/* OS(MAC_OS_X) - Mac OS X (not including iPhone OS) */ +/* OS(IOS) - iOS */ +/* OS(MAC_OS_X) - Mac OS X (not including iOS) */ #if OS(DARWIN) && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) \ || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \ || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)) -#define WTF_OS_IPHONE_OS 1 +#define WTF_OS_IOS 1 #elif OS(DARWIN) && defined(TARGET_OS_MAC) && TARGET_OS_MAC #define WTF_OS_MAC_OS_X 1 #endif @@ -341,7 +410,7 @@ /* OS(NETBSD) - NetBSD */ #if defined(__NetBSD__) -#define WTF_PLATFORM_NETBSD 1 +#define WTF_OS_NETBSD 1 #endif /* OS(OPENBSD) - OpenBSD */ @@ -371,9 +440,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 @@ -430,22 +496,22 @@ #define WTF_PLATFORM_WIN 1 #endif -/* PLATFORM(IPHONE) */ +/* PLATFORM(IOS) */ /* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */ #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) -#define WTF_PLATFORM_IPHONE 1 +#define WTF_PLATFORM_IOS 1 #endif -/* PLATFORM(IPHONE_SIMULATOR) */ +/* PLATFORM(IOS_SIMULATOR) */ #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR -#define WTF_PLATFORM_IPHONE 1 -#define WTF_PLATFORM_IPHONE_SIMULATOR 1 +#define WTF_PLATFORM_IOS 1 +#define WTF_PLATFORM_IOS_SIMULATOR 1 #else -#define WTF_PLATFORM_IPHONE_SIMULATOR 0 +#define WTF_PLATFORM_IOS_SIMULATOR 0 #endif -#if !defined(WTF_PLATFORM_IPHONE) -#define WTF_PLATFORM_IPHONE 0 +#if !defined(WTF_PLATFORM_IOS) +#define WTF_PLATFORM_IOS 0 #endif /* PLATFORM(ANDROID) */ @@ -458,48 +524,41 @@ /* Graphics engines */ /* PLATFORM(CG) and PLATFORM(CI) */ -#if PLATFORM(MAC) || PLATFORM(IPHONE) +#if PLATFORM(MAC) || PLATFORM(IOS) #define WTF_PLATFORM_CG 1 #endif -#if PLATFORM(MAC) && !PLATFORM(IPHONE) +#if PLATFORM(MAC) && !PLATFORM(IOS) #define WTF_PLATFORM_CI 1 #endif /* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */ #if PLATFORM(CHROMIUM) -#define ENABLE_HISTORY_ALWAYS_ASYNC 1 #if OS(DARWIN) #define WTF_PLATFORM_CG 1 #define WTF_PLATFORM_CI 1 #define WTF_USE_ATSUI 1 #define WTF_USE_CORE_TEXT 1 +#define WTF_USE_ICCJPEG 1 #else #define WTF_PLATFORM_SKIA 1 +#define WTF_USE_CHROMIUM_NET 1 #endif #endif +#if PLATFORM(BREWMP) +#define WTF_PLATFORM_SKIA 1 +#endif + #if PLATFORM(GTK) #define WTF_PLATFORM_CAIRO 1 #endif -/* OS(WINCE) && PLATFORM(QT) - We can not determine the endianess at compile time. For - Qt for Windows CE the endianess is specified in the - device specific makespec -*/ -#if OS(WINCE) && PLATFORM(QT) -# include <QtGlobal> -# undef WTF_CPU_BIG_ENDIAN -# undef WTF_CPU_MIDDLE_ENDIAN -# if Q_BYTE_ORDER == Q_BIG_ENDIAN -# define WTF_CPU_BIG_ENDIAN 1 -# endif - -# include <ce_time.h> +#if OS(WINCE) +#include <ce_time.h> #endif -#if (PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN) || (PLATFORM(QT) && OS(DARWIN) && !ENABLE(SINGLE_THREADED))) && !defined(ENABLE_JSC_MULTIPLE_THREADS) +#if (PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(WIN) || (PLATFORM(QT) && OS(DARWIN) && !ENABLE(SINGLE_THREADED))) && !defined(ENABLE_JSC_MULTIPLE_THREADS) #define ENABLE_JSC_MULTIPLE_THREADS 1 #endif @@ -509,16 +568,6 @@ #endif #if OS(WINCE) && !PLATFORM(QT) -#undef ENABLE_JSC_MULTIPLE_THREADS -#define ENABLE_JSC_MULTIPLE_THREADS 0 -#define USE_SYSTEM_MALLOC 0 -#define ENABLE_ICONDATABASE 0 -#define ENABLE_JAVASCRIPT_DEBUGGER 0 -#define ENABLE_FTPDIR 0 -#define ENABLE_PAN_SCROLLING 0 -#define ENABLE_WML 1 -#define HAVE_ACCESSIBILITY 0 - #define NOMINMAX /* Windows min and max conflict with standard macros */ #define NOSHLWAPI /* shlwapi.h not available on WinCe */ @@ -528,58 +577,70 @@ #define _INC_ASSERT /* disable "assert.h" */ #define assert(x) -/* _countof is only included in CE6; for CE5 we need to define it ourself */ -#ifndef _countof -#define _countof(x) (sizeof(x) / sizeof((x)[0])) -#endif - #endif /* OS(WINCE) && !PLATFORM(QT) */ #if PLATFORM(QT) #define WTF_USE_QT4_UNICODE 1 #elif OS(WINCE) #define WTF_USE_WINCE_UNICODE 1 +#elif PLATFORM(BREWMP) +#define WTF_USE_BREWMP_UNICODE 1 #elif PLATFORM(GTK) /* The GTK+ Unicode backend is configurable */ #else #define WTF_USE_ICU_UNICODE 1 #endif -#if PLATFORM(MAC) && !PLATFORM(IPHONE) +#if PLATFORM(MAC) && !PLATFORM(IOS) #define WTF_PLATFORM_CF 1 #define WTF_USE_PTHREADS 1 #define HAVE_PTHREAD_RWLOCK 1 #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 #endif #define HAVE_READLINE 1 #define HAVE_RUNLOOP_TIMER 1 -#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */ +#define ENABLE_FULLSCREEN_API 1 +#define ENABLE_SMOOTH_SCROLLING 1 +#endif /* PLATFORM(MAC) && !PLATFORM(IOS) */ + +#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(BREWMP) +#define ENABLE_SINGLE_THREADED 1 #endif #if PLATFORM(QT) && OS(DARWIN) #define WTF_PLATFORM_CF 1 #endif -#if PLATFORM(IPHONE) +#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) && !PLATFORM(GTK) && !PLATFORM(QT) +#define ENABLE_PURGEABLE_MEMORY 1 +#endif + +#if PLATFORM(IOS) #define ENABLE_CONTEXT_MENUS 0 #define ENABLE_DRAG_SUPPORT 0 #define ENABLE_FTPDIR 1 #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,23 +654,33 @@ #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. */ #define ENABLE_TEXT_CARET 1 #define ENABLE_JAVASCRIPT_DEBUGGER 0 #define ENABLE_ORIENTATION_EVENTS 1 +#if !defined(ENABLE_JIT) && !ENABLE(ANDROID_JSC_JIT) +#define ENABLE_JIT 0 +#endif #endif -#if PLATFORM(WIN) -#define WTF_USE_WININET 1 +#if PLATFORM(WIN) && !OS(WINCE) +#define WTF_PLATFORM_CF 1 +#define WTF_USE_PTHREADS 0 #endif #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 @@ -633,8 +704,12 @@ #define USE_SYSTEM_MALLOC 1 #endif +#if PLATFORM(BREWMP_SIMULATOR) +#define ENABLE_JIT 0 +#endif + #if !defined(HAVE_ACCESSIBILITY) -#if PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM) +#if PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM) #define HAVE_ACCESSIBILITY 1 #endif #endif /* !defined(HAVE_ACCESSIBILITY) */ @@ -663,11 +738,12 @@ #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMEB_H 1 -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD) #define HAVE_DISPATCH_H 1 +#define HAVE_HOSTED_CORE_ANIMATION 1 -#if !PLATFORM(IPHONE) && !PLATFORM(QT) +#if !PLATFORM(IOS) #define HAVE_MADV_FREE_REUSE 1 #define HAVE_MADV_FREE 1 #define HAVE_PTHREAD_SETNAME_NP 1 @@ -675,7 +751,7 @@ #endif -#if PLATFORM(IPHONE) +#if PLATFORM(IOS) #define HAVE_MADV_FREE 1 #endif @@ -685,6 +761,8 @@ #define HAVE_ERRNO_H 0 #else #define HAVE_SYS_TIMEB_H 1 +#define HAVE_ALIGNED_MALLOC 1 +#define HAVE_ISDEBUGGERPRESENT 1 #endif #define HAVE_VIRTUALALLOC 1 @@ -741,8 +819,20 @@ #endif +#if HAVE(MMAP) || (HAVE(VIRTUALALLOC) && HAVE(ALIGNED_MALLOC)) +#define HAVE_PAGE_ALLOCATE_ALIGNED 1 +#endif +#if HAVE(MMAP) +#define HAVE_PAGE_ALLOCATE_AT 1 +#endif + /* ENABLE macro defaults */ +#if PLATFORM(QT) +/* We must not 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) @@ -781,14 +871,22 @@ #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) #define ENABLE_NETSCAPE_PLUGIN_API 1 #endif +#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE) +#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0 +#endif + +#if !defined(ENABLE_PURGEABLE_MEMORY) +#define ENABLE_PURGEABLE_MEMORY 0 +#endif + #if !defined(WTF_USE_PLUGIN_HOST_PROCESS) #define WTF_USE_PLUGIN_HOST_PROCESS 0 #endif @@ -801,6 +899,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 +923,10 @@ #define ENABLE_NOTIFICATIONS 0 #endif +#if PLATFORM(IOS) +#define ENABLE_TEXT_CARET 0 +#endif + #if !defined(ENABLE_TEXT_CARET) #define ENABLE_TEXT_CARET 1 #endif @@ -839,90 +946,73 @@ #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0 #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 !defined(ENABLE_FULLSCREEN_API) +#define ENABLE_FULLSCREEN_API 0 +#endif + +#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) +#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) \ + || (CPU(IA64) && !CPU(IA64_32)) \ + || CPU(ALPHA) \ + || CPU(SPARC64) \ + || CPU(S390X) \ + || CPU(PPC64) #define WTF_USE_JSVALUE64 1 -#elif CPU(ARM) || CPU(PPC64) -#define WTF_USE_JSVALUE32 1 -#elif OS(WINDOWS) && COMPILER(MINGW) -/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg -on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ -#define WTF_USE_JSVALUE32 1 #else #define WTF_USE_JSVALUE32_64 1 #endif -#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */ +#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */ #if !defined(ENABLE_REPAINT_THROTTLING) #define ENABLE_REPAINT_THROTTLING 0 #endif -#if !defined(ENABLE_JIT) - -/* The JIT is tested & working on x86_64 Mac */ -#if CPU(X86_64) && PLATFORM(MAC) - #define ENABLE_JIT 1 -/* The JIT is tested & working on x86 Mac */ -#elif CPU(X86) && PLATFORM(MAC) - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif CPU(ARM_THUMB2) && PLATFORM(IPHONE) - #define ENABLE_JIT 1 -/* The JIT is tested & working on Android */ -#elif CPU(ARM_THUMB2) && PLATFORM(ANDROID) && ENABLE(ANDROID_JSC_JIT) - #define ENABLE_JIT 1 -/* The JIT is tested & working on x86 Windows */ -#elif CPU(X86) && PLATFORM(WIN) - #define ENABLE_JIT 1 -#endif - -#if PLATFORM(QT) || PLATFORM(WX) -#if CPU(X86_64) && OS(DARWIN) - #define ENABLE_JIT 1 -#elif CPU(X86) && OS(DARWIN) - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#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) && OS(WINDOWS) && COMPILER(MSVC) - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 -#elif CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100 - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100 - #define ENABLE_JIT 1 -#elif CPU(ARM_TRADITIONAL) && OS(LINUX) - #define ENABLE_JIT 1 -#endif -#endif /* PLATFORM(QT) */ - -#endif /* !defined(ENABLE_JIT) */ - -/* CPU architecture specific optimizations */ -#if CPU(ARM_TRADITIONAL) -#if ENABLE(JIT) && !defined(ENABLE_JIT_OPTIMIZE_MOD) && WTF_ARM_ARCH_AT_LEAST(5) -#define ENABLE_JIT_OPTIMIZE_MOD 1 -#endif +/* Disable the JIT on versiond of GCC prior to 4.1 */ +#if !defined(ENABLE_JIT) && COMPILER(GCC) && !GCC_VERSION_AT_LEAST(4,1,0) +#define ENABLE_JIT 0 #endif -#if ENABLE(JIT) -#ifndef ENABLE_JIT_OPTIMIZE_CALL -#define ENABLE_JIT_OPTIMIZE_CALL 1 -#endif -#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL -#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 +/* JIT is not implemented for 64 bit on MSVC */ +#if !defined(ENABLE_JIT) && COMPILER(MSVC) && CPU(X86_64) +#define ENABLE_JIT 0 #endif -#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS -#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1 + +/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */ +#if !defined(ENABLE_JIT) \ + && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS)) \ + && (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4,1,0)) \ + && !OS(WINCE) +#define ENABLE_JIT 1 #endif -#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS -#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1 + +/* Ensure that either the JIT or the interpreter has been enabled. */ +#if !defined(ENABLE_INTERPRETER) && !ENABLE(JIT) +#define ENABLE_INTERPRETER 1 #endif -#ifndef ENABLE_JIT_OPTIMIZE_MOD -#define ENABLE_JIT_OPTIMIZE_MOD 0 +#if !(ENABLE(JIT) || ENABLE(INTERPRETER)) +#error You have to have at least one execution model enabled to build JSC #endif + +/* Configure the JIT */ +#if ENABLE(JIT) + #if CPU(ARM) + #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5) + #define ENABLE_JIT_USE_SOFT_MODULO 1 + #endif + #endif + + #ifndef ENABLE_JIT_OPTIMIZE_CALL + #define ENABLE_JIT_OPTIMIZE_CALL 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL + #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS + #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS + #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1 + #endif #endif #if CPU(X86) && COMPILER(MSVC) @@ -933,98 +1023,81 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define JSC_HOST_CALL #endif -#if COMPILER(GCC) && !ENABLE(JIT) +/* Configure the interpreter */ +#if COMPILER(GCC) #define HAVE_COMPUTED_GOTO 1 #endif - -#if ENABLE(JIT) && defined(COVERAGE) - #define WTF_USE_INTERPRETER 0 -#else - #define WTF_USE_INTERPRETER 1 +#if HAVE(COMPUTED_GOTO) && ENABLE(INTERPRETER) +#define ENABLE_COMPUTED_GOTO_INTERPRETER 1 #endif -/* Yet Another Regex Runtime. */ -#if !defined(ENABLE_YARR_JIT) - -/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */ -#if (CPU(X86) && PLATFORM(MAC)) \ - || (CPU(X86_64) && PLATFORM(MAC)) \ - || (CPU(ARM_THUMB2) && PLATFORM(IPHONE)) \ - || (CPU(ARM_THUMB2) && PLATFORM(ANDROID) && ENABLE(ANDROID_JSC_JIT)) \ - || (CPU(X86) && PLATFORM(WIN)) \ - || (CPU(X86) && PLATFORM(WX)) -#define ENABLE_YARR 1 -#define ENABLE_YARR_JIT 1 -#endif +/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc. Results dumped at exit */ +#define ENABLE_REGEXP_TRACING 0 -#if PLATFORM(QT) -#if (CPU(X86) && OS(WINDOWS) && COMPILER(MINGW) && 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)) -#define ENABLE_YARR 1 +/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */ +#if ENABLE(JIT) && !defined(ENABLE_YARR_JIT) #define ENABLE_YARR_JIT 1 #endif -#endif - -#endif /* !defined(ENABLE_YARR_JIT) */ - -/* Sanity Check */ -#if ENABLE(YARR_JIT) && !ENABLE(YARR) -#error "YARR_JIT requires YARR" -#endif #if ENABLE(JIT) || ENABLE(YARR_JIT) #define ENABLE_ASSEMBLER 1 #endif /* Setting this flag prevents the assembler from using RWX memory; this may improve security but currectly comes at a significant performance cost. */ -#if PLATFORM(IPHONE) +#if PLATFORM(IOS) #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1 #else #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0 #endif +/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in. + On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */ +#if ENABLE(ASSEMBLER) +#if CPU(X86_64) +#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1 +#else +#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1 +#endif +#endif + #if !defined(ENABLE_PAN_SCROLLING) && OS(WINDOWS) #define ENABLE_PAN_SCROLLING 1 #endif -/* Use the QXmlStreamReader implementation for XMLTokenizer */ +#if !defined(ENABLE_SMOOTH_SCROLLING) +#define ENABLE_SMOOTH_SCROLLING 0 +#endif + +/* Use the QXmlStreamReader implementation for XMLDocumentParser */ /* Use the QXmlQuery implementation for XSLTProcessor */ #if PLATFORM(QT) #define WTF_USE_QXMLSTREAM 1 #define WTF_USE_QXMLQUERY 1 #endif -#if !PLATFORM(QT) -#define WTF_USE_FONT_FAST_PATH 1 -#endif - -/* Accelerated compositing */ #if PLATFORM(MAC) -#if !defined(BUILDING_ON_TIGER) -#define WTF_USE_ACCELERATED_COMPOSITING 1 +/* Complex text framework */ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#define WTF_USE_ATSUI 0 +#define WTF_USE_CORE_TEXT 1 +#else +#define WTF_USE_ATSUI 1 +#define WTF_USE_CORE_TEXT 0 #endif #endif +/* Accelerated compositing */ #if PLATFORM(ANDROID) && !defined WTF_USE_ACCELERATED_COMPOSITING #define WTF_USE_ACCELERATED_COMPOSITING 1 +#define ENABLE_3D_RENDERING 1 #endif -#if PLATFORM(IPHONE) +#if (PLATFORM(MAC) && !defined(BUILDING_ON_TIGER)) || PLATFORM(IOS) || PLATFORM(QT) || (PLATFORM(WIN) && !OS(WINCE) &&!defined(WIN_CAIRO)) #define WTF_USE_ACCELERATED_COMPOSITING 1 #endif -/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with - with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and - off in one place. */ -#if PLATFORM(WIN) -#include "QuartzCorePresent.h" -#if QUARTZCORE_PRESENT -#define WTF_USE_ACCELERATED_COMPOSITING 1 -#define ENABLE_3D_RENDERING 1 -#endif +#if (PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IOS) +#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1 #endif #if COMPILER(GCC) @@ -1042,4 +1115,24 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JSC_ZOMBIES 0 +/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */ +#if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(QT) +#define WTF_USE_PLATFORM_STRATEGIES 1 +#endif + +/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location. + Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy. + pre-emptive permission policy is enabled by default for all client-based implementations. */ +#if ENABLE(CLIENT_BASED_GEOLOCATION) +#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1 +#endif + +#if CPU(ARM_THUMB2) +#define ENABLE_BRANCH_COMPACTION 1 +#endif + +#if ENABLE(GLIB_SUPPORT) +#include "GTypedefs.h" +#endif + #endif /* WTF_Platform_h */ diff --git a/JavaScriptCore/wtf/PlatformRefPtr.h b/JavaScriptCore/wtf/PlatformRefPtr.h new file mode 100644 index 0000000..8ac16cb --- /dev/null +++ b/JavaScriptCore/wtf/PlatformRefPtr.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2009 Martin Robinson + * + * 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 PlatformRefPtr_h +#define PlatformRefPtr_h + +#include "AlwaysInline.h" +#include "RefPtr.h" +#include <algorithm> + +namespace WTF { + +enum PlatformRefPtrAdoptType { PlatformRefPtrAdopt }; +template <typename T> inline T* refPlatformPtr(T*); +template <typename T> inline void derefPlatformPtr(T*); +template <typename T> class PlatformRefPtr; +template <typename T> PlatformRefPtr<T> adoptPlatformRef(T*); + +template <typename T> class PlatformRefPtr { +public: + PlatformRefPtr() : m_ptr(0) { } + + PlatformRefPtr(T* ptr) + : m_ptr(ptr) + { + if (ptr) + refPlatformPtr(ptr); + } + + PlatformRefPtr(const PlatformRefPtr& o) + : m_ptr(o.m_ptr) + { + if (T* ptr = m_ptr) + refPlatformPtr(ptr); + } + + template <typename U> PlatformRefPtr(const PlatformRefPtr<U>& o) + : m_ptr(o.get()) + { + if (T* ptr = m_ptr) + refPlatformPtr(ptr); + } + + ~PlatformRefPtr() + { + if (T* ptr = m_ptr) + derefPlatformPtr(ptr); + } + + void clear() + { + T* ptr = m_ptr; + m_ptr = 0; + if (ptr) + derefPlatformPtr(ptr); + } + + // Hash table deleted values, which are only constructed and never copied or destroyed. + PlatformRefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } + + T* get() const { return m_ptr; } + T& operator*() const { return *m_ptr; } + ALWAYS_INLINE T* operator->() const { 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* PlatformRefPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &PlatformRefPtr::m_ptr : 0; } + + PlatformRefPtr& operator=(const PlatformRefPtr&); + PlatformRefPtr& operator=(T*); + template <typename U> PlatformRefPtr& operator=(const PlatformRefPtr<U>&); + + void swap(PlatformRefPtr&); + friend PlatformRefPtr adoptPlatformRef<T>(T*); + +private: + static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + // Adopting constructor. + PlatformRefPtr(T* ptr, PlatformRefPtrAdoptType) : m_ptr(ptr) {} + + T* m_ptr; +}; + +template <typename T> inline PlatformRefPtr<T>& PlatformRefPtr<T>::operator=(const PlatformRefPtr<T>& o) +{ + T* optr = o.get(); + if (optr) + refPlatformPtr(optr); + T* ptr = m_ptr; + m_ptr = optr; + if (ptr) + derefPlatformPtr(ptr); + return *this; +} + +template <typename T> inline PlatformRefPtr<T>& PlatformRefPtr<T>::operator=(T* optr) +{ + T* ptr = m_ptr; + if (optr) + refPlatformPtr(optr); + m_ptr = optr; + if (ptr) + derefPlatformPtr(ptr); + return *this; +} + +template <class T> inline void PlatformRefPtr<T>::swap(PlatformRefPtr<T>& o) +{ + std::swap(m_ptr, o.m_ptr); +} + +template <class T> inline void swap(PlatformRefPtr<T>& a, PlatformRefPtr<T>& b) +{ + a.swap(b); +} + +template <typename T, typename U> inline bool operator==(const PlatformRefPtr<T>& a, const PlatformRefPtr<U>& b) +{ + return a.get() == b.get(); +} + +template <typename T, typename U> inline bool operator==(const PlatformRefPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template <typename T, typename U> inline bool operator==(T* a, const PlatformRefPtr<U>& b) +{ + return a == b.get(); +} + +template <typename T, typename U> inline bool operator!=(const PlatformRefPtr<T>& a, const PlatformRefPtr<U>& b) +{ + return a.get() != b.get(); +} + +template <typename T, typename U> inline bool operator!=(const PlatformRefPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template <typename T, typename U> inline bool operator!=(T* a, const PlatformRefPtr<U>& b) +{ + return a != b.get(); +} + +template <typename T, typename U> inline PlatformRefPtr<T> static_pointer_cast(const PlatformRefPtr<U>& p) +{ + return PlatformRefPtr<T>(static_cast<T*>(p.get())); +} + +template <typename T, typename U> inline PlatformRefPtr<T> const_pointer_cast(const PlatformRefPtr<U>& p) +{ + return PlatformRefPtr<T>(const_cast<T*>(p.get())); +} + +template <typename T> inline T* getPtr(const PlatformRefPtr<T>& p) +{ + return p.get(); +} + +template <typename T> PlatformRefPtr<T> adoptPlatformRef(T* p) +{ + return PlatformRefPtr<T>(p, PlatformRefPtrAdopt); +} + +} // namespace WTF + +using WTF::PlatformRefPtr; +using WTF::refPlatformPtr; +using WTF::derefPlatformPtr; +using WTF::adoptPlatformRef; +using WTF::static_pointer_cast; +using WTF::const_pointer_cast; + +#endif // PlatformRefPtr_h 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.cpp b/JavaScriptCore/wtf/RandomNumber.cpp index fc48263..7a9b6a8 100644 --- a/JavaScriptCore/wtf/RandomNumber.cpp +++ b/JavaScriptCore/wtf/RandomNumber.cpp @@ -44,24 +44,12 @@ extern "C" { #include <AEEAppGen.h> #include <AEESource.h> #include <AEEStdLib.h> +#include <wtf/brew/RefPtrBrew.h> +#include <wtf/brew/ShellBrew.h> #endif namespace WTF { -double weakRandomNumber() -{ -#if COMPILER(MSVC) && defined(_CRT_RAND_S) - // rand_s is incredibly slow on windows so we fall back on rand for Math.random - return (rand() + (rand() / (RAND_MAX + 1.0))) / (RAND_MAX + 1.0); -#elif PLATFORM(BREWMP) - uint32_t bits; - GETRAND(reinterpret_cast<byte*>(&bits), sizeof(uint32_t)); - return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0); -#else - return randomNumber(); -#endif -} - double randomNumber() { #if !ENABLE(JSC_MULTIPLE_THREADS) @@ -111,12 +99,8 @@ double randomNumber() return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53); #elif PLATFORM(BREWMP) uint32_t bits; - ISource* randomSource; - - IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell; - ISHELL_CreateInstance(shell, AEECLSID_RANDOM, reinterpret_cast<void**>(&randomSource)); - ISOURCE_Read(randomSource, reinterpret_cast<char*>(&bits), 4); - ISOURCE_Release(randomSource); + PlatformRefPtr<ISource> randomSource = createRefPtrInstance<ISource>(AEECLSID_RANDOM); + ISOURCE_Read(randomSource.get(), reinterpret_cast<char*>(&bits), 4); return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0); #else diff --git a/JavaScriptCore/wtf/RandomNumber.h b/JavaScriptCore/wtf/RandomNumber.h index fe1687c..f2e7e8f 100644 --- a/JavaScriptCore/wtf/RandomNumber.h +++ b/JavaScriptCore/wtf/RandomNumber.h @@ -32,11 +32,8 @@ namespace WTF { // cryptographically secure if possible on the target platform double randomNumber(); - // Returns a pseudo-random number in the range [0, 1), attempts to - // produce a reasonable "random" number fast. - // We only need this because rand_s is so slow on windows. - double weakRandomNumber(); - } +using WTF::randomNumber; + #endif diff --git a/JavaScriptCore/wtf/RandomNumberSeed.h b/JavaScriptCore/wtf/RandomNumberSeed.h index ae414c0..b53b506 100644 --- a/JavaScriptCore/wtf/RandomNumberSeed.h +++ b/JavaScriptCore/wtf/RandomNumberSeed.h @@ -64,6 +64,8 @@ inline void initializeRandomNumberGenerator() init_by_array(initializationBuffer, 4); #elif COMPILER(MSVC) && defined(_CRT_RAND_S) // On Windows we use rand_s which initialises itself +#elif PLATFORM(BREWMP) + // On Brew MP we use AEECLSID_RANDOM which initialises itself #elif OS(UNIX) // srandomdev is not guaranteed to exist on linux so we use this poor seed, this should be improved timeval time; @@ -74,15 +76,6 @@ inline void initializeRandomNumberGenerator() #endif } -inline void initializeWeakRandomNumberGenerator() -{ -#if COMPILER(MSVC) && defined(_CRT_RAND_S) - // We need to initialise windows rand() explicitly for Math.random - unsigned seed = 0; - rand_s(&seed); - srand(seed); -#endif -} } #endif diff --git a/JavaScriptCore/wtf/RefCounted.h b/JavaScriptCore/wtf/RefCounted.h index 761a856..8d8b302 100644 --- a/JavaScriptCore/wtf/RefCounted.h +++ b/JavaScriptCore/wtf/RefCounted.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 @@ -21,8 +21,8 @@ #ifndef RefCounted_h #define RefCounted_h -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> +#include "Assertions.h" +#include "Noncopyable.h" namespace WTF { @@ -34,6 +34,7 @@ public: void ref() { ASSERT(!m_deletionHasBegun); + ASSERT(!m_adoptionIsRequired); ++m_refCount; } @@ -48,23 +49,37 @@ public: return m_refCount; } + void relaxAdoptionRequirement() + { +#ifndef NDEBUG + ASSERT(!m_deletionHasBegun); + ASSERT(m_adoptionIsRequired); + m_adoptionIsRequired = false; +#endif + } + protected: RefCountedBase() : m_refCount(1) #ifndef NDEBUG , m_deletionHasBegun(false) + , m_adoptionIsRequired(true) #endif { } ~RefCountedBase() { + ASSERT(m_deletionHasBegun); + ASSERT(!m_adoptionIsRequired); } // Returns whether the pointer should be freed or not. bool derefBase() { ASSERT(!m_deletionHasBegun); + ASSERT(!m_adoptionIsRequired); + ASSERT(m_refCount > 0); if (m_refCount == 1) { #ifndef NDEBUG @@ -91,17 +106,32 @@ protected: #endif private: - template<class T> - friend class CrossThreadRefCounted; + template<typename T> friend class CrossThreadRefCounted; + +#ifndef NDEBUG + friend void adopted(RefCountedBase*); +#endif int m_refCount; #ifndef NDEBUG bool m_deletionHasBegun; + bool m_adoptionIsRequired; #endif }; +#ifndef NDEBUG + +inline void adopted(RefCountedBase* object) +{ + if (!object) + return; + ASSERT(!object->m_deletionHasBegun); + object->m_adoptionIsRequired = false; +} -template<class T> class RefCounted : public RefCountedBase, public Noncopyable { +#endif + +template<typename T> class RefCounted : public RefCountedBase, public Noncopyable { public: void deref() { @@ -115,7 +145,9 @@ protected: } }; -template<class T> class RefCountedCustomAllocated : public RefCountedBase, public NoncopyableCustomAllocated { +template<typename T> class RefCountedCustomAllocated : public RefCountedBase { + WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); + public: void deref() { diff --git a/JavaScriptCore/wtf/RefPtr.h b/JavaScriptCore/wtf/RefPtr.h index 84e841c..6afa886 100644 --- a/JavaScriptCore/wtf/RefPtr.h +++ b/JavaScriptCore/wtf/RefPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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 @@ -18,11 +18,12 @@ * */ +// RefPtr and PassRefPtr are documented at http://webkit.org/coding/RefPtr.html + #ifndef WTF_RefPtr_h #define WTF_RefPtr_h #include <algorithm> -#include "AlwaysInline.h" #include "FastAllocBase.h" #include "PassRefPtr.h" @@ -30,34 +31,34 @@ namespace WTF { enum PlacementNewAdoptType { PlacementNewAdopt }; - template <typename T> class PassRefPtr; - template <typename T> class NonNullPassRefPtr; + template<typename T> class PassRefPtr; + template<typename T> class NonNullPassRefPtr; enum HashTableDeletedValueType { HashTableDeletedValue }; - template <typename T> class RefPtr : public FastAllocBase { + template<typename T> class RefPtr : public FastAllocBase { public: - RefPtr() : m_ptr(0) { } - RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); } - RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { T* ptr = m_ptr; refIfNotNull(ptr); } - // see comment in PassRefPtr.h for why this takes const reference - template <typename U> RefPtr(const PassRefPtr<U>&); - template <typename U> RefPtr(const NonNullPassRefPtr<U>&); + ALWAYS_INLINE RefPtr() : m_ptr(0) { } + ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); } + ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(m_ptr); } + template<typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { refIfNotNull(m_ptr); } + + // See comments in PassRefPtr.h for an explanation of why these takes const references. + template<typename U> RefPtr(const PassRefPtr<U>&); + template<typename U> RefPtr(const NonNullPassRefPtr<U>&); // Special constructor for cases where we overwrite an object in place. - RefPtr(PlacementNewAdoptType) { } + ALWAYS_INLINE RefPtr(PlacementNewAdoptType) { } // Hash table deleted values, which are only constructed and never copied or destroyed. RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } - ~RefPtr() { derefIfNotNull(m_ptr); } - - template <typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { T* ptr = m_ptr; refIfNotNull(ptr); } - + ALWAYS_INLINE ~RefPtr() { derefIfNotNull(m_ptr); } + T* get() const { return m_ptr; } - void clear() { derefIfNotNull(m_ptr); m_ptr = 0; } + void clear(); PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; } T& operator*() const { return *m_ptr; } @@ -73,29 +74,37 @@ namespace WTF { RefPtr& operator=(T*); RefPtr& operator=(const PassRefPtr<T>&); RefPtr& operator=(const NonNullPassRefPtr<T>&); - template <typename U> RefPtr& operator=(const RefPtr<U>&); - template <typename U> RefPtr& operator=(const PassRefPtr<U>&); - template <typename U> RefPtr& operator=(const NonNullPassRefPtr<U>&); + RefPtr& operator=(std::nullptr_t) { clear(); return *this; } + template<typename U> RefPtr& operator=(const RefPtr<U>&); + template<typename U> RefPtr& operator=(const PassRefPtr<U>&); + template<typename U> RefPtr& operator=(const NonNullPassRefPtr<U>&); void swap(RefPtr&); - private: static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + private: T* m_ptr; }; - template <typename T> template <typename U> inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o) - : m_ptr(o.releaseRef()) + template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o) + : m_ptr(o.leakRef()) + { + } + + template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o) + : m_ptr(o.leakRef()) { } - template <typename T> template <typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o) - : m_ptr(o.releaseRef()) + template<typename T> inline void RefPtr<T>::clear() { + T* ptr = m_ptr; + m_ptr = 0; + derefIfNotNull(ptr); } - template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o) + template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o) { T* optr = o.get(); refIfNotNull(optr); @@ -105,7 +114,7 @@ namespace WTF { return *this; } - template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o) + template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o) { T* optr = o.get(); refIfNotNull(optr); @@ -115,7 +124,7 @@ namespace WTF { return *this; } - template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr) + template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr) { refIfNotNull(optr); T* ptr = m_ptr; @@ -124,89 +133,89 @@ namespace WTF { return *this; } - template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o) + template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o) { T* ptr = m_ptr; - m_ptr = o.releaseRef(); + m_ptr = o.leakRef(); derefIfNotNull(ptr); return *this; } - template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o) + template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o) { T* ptr = m_ptr; - m_ptr = o.releaseRef(); + m_ptr = o.leakRef(); derefIfNotNull(ptr); return *this; } - template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o) + template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o) { T* ptr = m_ptr; - m_ptr = o.releaseRef(); + m_ptr = o.leakRef(); derefIfNotNull(ptr); return *this; } - template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o) + template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o) { T* ptr = m_ptr; - m_ptr = o.releaseRef(); + m_ptr = o.leakRef(); derefIfNotNull(ptr); return *this; } - template <class T> inline void RefPtr<T>::swap(RefPtr<T>& o) + template<class T> inline void RefPtr<T>::swap(RefPtr<T>& o) { std::swap(m_ptr, o.m_ptr); } - template <class T> inline void swap(RefPtr<T>& a, RefPtr<T>& b) + template<class T> inline void swap(RefPtr<T>& a, RefPtr<T>& b) { a.swap(b); } - template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, U* b) { return a.get() == b; } - template <typename T, typename U> inline bool operator==(T* a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator==(T* a, const RefPtr<U>& b) { return a == b.get(); } - template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, U* b) { return a.get() != b; } - template <typename T, typename U> inline bool operator!=(T* a, const RefPtr<U>& b) + template<typename T, typename U> inline bool operator!=(T* a, const RefPtr<U>& b) { return a != b.get(); } - template <typename T, typename U> inline RefPtr<T> static_pointer_cast(const RefPtr<U>& p) + template<typename T, typename U> inline RefPtr<T> static_pointer_cast(const RefPtr<U>& p) { return RefPtr<T>(static_cast<T*>(p.get())); } - template <typename T, typename U> inline RefPtr<T> const_pointer_cast(const RefPtr<U>& p) + template<typename T, typename U> inline RefPtr<T> const_pointer_cast(const RefPtr<U>& p) { return RefPtr<T>(const_cast<T*>(p.get())); } - template <typename T> inline T* getPtr(const RefPtr<T>& p) + template<typename T> inline T* getPtr(const RefPtr<T>& p) { return p.get(); } diff --git a/JavaScriptCore/wtf/RetainPtr.h b/JavaScriptCore/wtf/RetainPtr.h index 77f25e0..8a14cfe 100644 --- a/JavaScriptCore/wtf/RetainPtr.h +++ b/JavaScriptCore/wtf/RetainPtr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2010 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 @@ -21,6 +21,8 @@ #ifndef RetainPtr_h #define RetainPtr_h +#include "HashTraits.h" +#include "NullPtr.h" #include "TypeTraits.h" #include <algorithm> #include <CoreFoundation/CoreFoundation.h> @@ -47,7 +49,7 @@ namespace WTF { } #endif - template <typename T> class RetainPtr { + template<typename T> class RetainPtr { public: typedef typename RemovePointer<T>::Type ValueType; typedef ValueType* PtrType; @@ -60,14 +62,19 @@ namespace WTF { RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); } + // Hash table deleted values, which are only constructed and never copied or destroyed. + RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } + ~RetainPtr() { if (PtrType ptr = m_ptr) CFRelease(ptr); } - template <typename U> RetainPtr(const RetainPtr<U>& o) : m_ptr(o.get()) { if (PtrType ptr = m_ptr) CFRetain(ptr); } + template<typename U> RetainPtr(const RetainPtr<U>&); PtrType get() const { return m_ptr; } - - PtrType releaseRef() { PtrType tmp = m_ptr; m_ptr = 0; return tmp; } - + + void clear(); + PtrType leakRef() WARN_UNUSED_RETURN; + PtrType operator->() const { return m_ptr; } bool operator!() const { return !m_ptr; } @@ -77,20 +84,48 @@ namespace WTF { operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; } RetainPtr& operator=(const RetainPtr&); - template <typename U> RetainPtr& operator=(const RetainPtr<U>&); + template<typename U> RetainPtr& operator=(const RetainPtr<U>&); RetainPtr& operator=(PtrType); - template <typename U> RetainPtr& operator=(U*); + template<typename U> RetainPtr& operator=(U*); + RetainPtr& operator=(std::nullptr_t) { clear(); return *this; } void adoptCF(PtrType); void adoptNS(PtrType); void swap(RetainPtr&); + // FIXME: Remove releaseRef once we change all callers to call leakRef instead. + PtrType releaseRef() { return leakRef(); } + private: + static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + PtrType m_ptr; }; - template <typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o) + template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o) + : m_ptr(o.get()) + { + if (PtrType ptr = m_ptr) + CFRetain(ptr); + } + + template<typename T> inline void RetainPtr<T>::clear() + { + if (PtrType ptr = m_ptr) { + m_ptr = 0; + CFRelease(ptr); + } + } + + template<typename T> inline typename RetainPtr<T>::PtrType RetainPtr<T>::leakRef() + { + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; + } + + template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o) { PtrType optr = o.get(); if (optr) @@ -102,7 +137,7 @@ namespace WTF { return *this; } - template <typename T> template <typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o) + template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o) { PtrType optr = o.get(); if (optr) @@ -114,7 +149,7 @@ namespace WTF { return *this; } - template <typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr) + template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr) { if (optr) CFRetain(optr); @@ -125,7 +160,7 @@ namespace WTF { return *this; } - template <typename T> inline void RetainPtr<T>::adoptCF(PtrType optr) + template<typename T> inline void RetainPtr<T>::adoptCF(PtrType optr) { PtrType ptr = m_ptr; m_ptr = optr; @@ -133,7 +168,7 @@ namespace WTF { CFRelease(ptr); } - template <typename T> inline void RetainPtr<T>::adoptNS(PtrType optr) + template<typename T> inline void RetainPtr<T>::adoptNS(PtrType optr) { adoptNSReference(optr); @@ -143,7 +178,7 @@ namespace WTF { CFRelease(ptr); } - template <typename T> template <typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr) + template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr) { if (optr) CFRetain(optr); @@ -154,45 +189,62 @@ namespace WTF { return *this; } - template <class T> inline void RetainPtr<T>::swap(RetainPtr<T>& o) + template<typename T> inline void RetainPtr<T>::swap(RetainPtr<T>& o) { std::swap(m_ptr, o.m_ptr); } - template <class T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b) + template<typename T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b) { a.swap(b); } - template <typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b) + template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b) { return a.get() == b.get(); } - template <typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b) { return a.get() == b; } - template <typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b) + template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b) { return a == b.get(); } - template <typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b) + template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b) { return a.get() != b.get(); } - template <typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b) + template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b) { return a.get() != b; } - template <typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b) + template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b) { return a != b.get(); } + + template<typename P> struct HashTraits<RetainPtr<P> > : GenericHashTraits<RetainPtr<P> > { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(RetainPtr<P>& slot) { new (&slot) RetainPtr<P>(HashTableDeletedValue); } + static bool isDeletedValue(const RetainPtr<P>& value) { return value == reinterpret_cast<P*>(-1); } + }; + + template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<P*> { + using PtrHash<P*>::hash; + static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); } + using PtrHash<P*>::equal; + static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; } + static bool equal(P* a, const RetainPtr<P>& b) { return a == b; } + static bool equal(const RetainPtr<P>& a, P* b) { return a == b; } + }; + + template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; }; } // namespace WTF diff --git a/JavaScriptCore/wtf/SizeLimits.cpp b/JavaScriptCore/wtf/SizeLimits.cpp new file mode 100644 index 0000000..4e481bb --- /dev/null +++ b/JavaScriptCore/wtf/SizeLimits.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include "config.h" + +#include <wtf/Assertions.h> +#include <wtf/CrossThreadRefCounted.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WTF { + +#ifndef NDEBUG +struct StructWithIntAndTwoBools { int a; bool b; bool c; }; +static const size_t refCountedExtraDebugSize = sizeof(StructWithIntAndTwoBools) - sizeof(int); +#else +static const size_t refCountedExtraDebugSize = 0; +#endif + +COMPILE_ASSERT(sizeof(OwnPtr<int>) == sizeof(int*), OwnPtr_should_stay_small); +COMPILE_ASSERT(sizeof(PassRefPtr<RefCounted<int> >) == sizeof(int*), PassRefPtr_should_stay_small); +COMPILE_ASSERT(sizeof(RefCounted<int>) == sizeof(int) + refCountedExtraDebugSize, RefCounted_should_stay_small); +COMPILE_ASSERT(sizeof(RefCountedCustomAllocated<int>) == sizeof(int) + refCountedExtraDebugSize, RefCountedCustomAllocated_should_stay_small); +COMPILE_ASSERT(sizeof(RefPtr<RefCounted<int> >) == sizeof(int*), RefPtr_should_stay_small); +COMPILE_ASSERT(sizeof(Vector<int>) == 3 * sizeof(int*), Vector_should_stay_small); + +} 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..4bb0076 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 @@ -52,31 +51,69 @@ #define STRINGIZE(exp) #exp #define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp) +/* + * The reinterpret_cast<Type1*>([pointer to Type2]) expressions - where + * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC: + * increases required alignment of target type. + * + * An implicit or an extra static_cast<void*> bypasses the warning. + * For more info see the following bugzilla entries: + * - https://bugs.webkit.org/show_bug.cgi?id=38045 + * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976 + */ +#if (CPU(ARM) || CPU(MIPS)) && COMPILER(GCC) +template<typename Type> +bool isPointerTypeAlignmentOkay(Type* ptr) +{ + return !(reinterpret_cast<intptr_t>(ptr) % __alignof__(Type)); +} + +template<typename TypePtr> +TypePtr reinterpret_cast_ptr(void* ptr) +{ + ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr))); + return reinterpret_cast<TypePtr>(ptr); +} + +template<typename TypePtr> +TypePtr reinterpret_cast_ptr(const void* ptr) +{ + ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr))); + return reinterpret_cast<TypePtr>(ptr); +} +#else +#define reinterpret_cast_ptr reinterpret_cast +#endif + namespace WTF { - /* - * C++'s idea of a reinterpret_cast lacks sufficient cojones. - */ - template<typename TO, typename FROM> - TO bitwise_cast(FROM from) - { - COMPILE_ASSERT(sizeof(TO) == sizeof(FROM), WTF_bitwise_cast_sizeof_casted_types_is_equal); - union { - FROM from; - TO to; - } u; - u.from = from; - return u.to; - } +/* + * C++'s idea of a reinterpret_cast lacks sufficient cojones. + */ +template<typename TO, typename FROM> +inline TO bitwise_cast(FROM from) +{ + COMPILE_ASSERT(sizeof(TO) == sizeof(FROM), WTF_bitwise_cast_sizeof_casted_types_is_equal); + union { + FROM from; + TO to; + } u; + u.from = from; + return u.to; +} + +// Returns a count of the number of bits set in 'bits'. +inline size_t bitCount(unsigned bits) +{ + bits = bits - ((bits >> 1) & 0x55555555); + bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); + return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} - // Returns a count of the number of bits set in 'bits'. - inline size_t bitCount(unsigned bits) - { - bits = bits - ((bits >> 1) & 0x55555555); - bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); - return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; - } +// Macro that returns a compile time constant with the length of an array, but gives an error if passed a non-array. +template<typename T, size_t Size> char (&ArrayLengthHelperFunction(T (&)[Size]))[Size]; +#define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array)) } // namespace WTF -#endif +#endif // WTF_StdLibExtras_h diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index b1ec09f..473bb22 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Inc. All rights reserved. + * Copyright (C) 2006, 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 @@ -28,6 +28,7 @@ #include <stdarg.h> #include <stdio.h> +#include <string.h> #if HAVE(STRINGS_H) #include <strings.h> @@ -43,17 +44,30 @@ inline int snprintf(char* buffer, size_t count, const char* format, ...) va_start(args, format); result = _vsnprintf(buffer, count, format, args); va_end(args); + + // In the case where the string entirely filled the buffer, _vsnprintf will not + // null-terminate it, but snprintf must. + if (count > 0) + buffer[count - 1] = '\0'; + return result; } -#if COMPILER(MSVC7) || OS(WINCE) - -inline int vsnprintf(char* buffer, size_t count, const char* format, va_list args) +inline double wtf_vsnprintf(char* buffer, size_t count, const char* format, va_list args) { - return _vsnprintf(buffer, count, format, args); + int result = _vsnprintf(buffer, count, format, args); + + // In the case where the string entirely filled the buffer, _vsnprintf will not + // null-terminate it, but vsnprintf must. + if (count > 0) + buffer[count - 1] = '\0'; + + return result; } -#endif +// Work around a difference in Microsoft's implementation of vsnprintf, where +// vsnprintf does not null terminate the buffer. WebKit can rely on the null termination. +#define vsnprintf(buffer, count, format, args) wtf_vsnprintf(buffer, count, format, args) #if OS(WINCE) @@ -86,7 +100,7 @@ inline int strcasecmp(const char* s1, const char* s2) #endif -#if OS(WINDOWS) || OS(LINUX) || OS(SOLARIS) +#if COMPILER(MSVC) || COMPILER(RVCT) || OS(WINDOWS) || OS(LINUX) || OS(SOLARIS) // FIXME: should check HAVE_STRNSTR inline char* strnstr(const char* buffer, const char* target, size_t bufferLength) diff --git a/JavaScriptCore/wtf/StringHashFunctions.h b/JavaScriptCore/wtf/StringHashFunctions.h deleted file mode 100644 index 07f117f..0000000 --- a/JavaScriptCore/wtf/StringHashFunctions.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2005, 2006, 2008, 2010 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 WTF_StringHashFunctions_h -#define WTF_StringHashFunctions_h - -#include <wtf/unicode/Unicode.h> - -namespace WTF { - -// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's -static const unsigned stringHashingStartValue = 0x9e3779b9U; - -// stringHash methods based on Paul Hsieh's SuperFastHash. -// http://www.azillionmonkeys.com/qed/hash.html -// char* data is interpreted as latin-encoded (zero extended to 16 bits). - -inline unsigned stringHash(const UChar* data, unsigned length) -{ - unsigned hash = WTF::stringHashingStartValue; - unsigned rem = length & 1; - length >>= 1; - - // Main loop - for (; length > 0; length--) { - hash += data[0]; - unsigned tmp = (data[1] << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += data[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; - - hash &= 0x7fffffff; - - // 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 - if (hash == 0) - hash = 0x40000000; - - return hash; -} - -inline unsigned stringHash(const char* data, unsigned length) -{ - unsigned hash = WTF::stringHashingStartValue; - unsigned rem = length & 1; - length >>= 1; - - // Main loop - for (; length > 0; length--) { - hash += static_cast<unsigned char>(data[0]); - unsigned tmp = (static_cast<unsigned char>(data[1]) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += static_cast<unsigned char>(data[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; - - hash &= 0x7fffffff; - - // 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 - if (hash == 0) - hash = 0x40000000; - - return hash; -} - -inline unsigned stringHash(const char* data) -{ - unsigned hash = WTF::stringHashingStartValue; - - // Main loop - for (;;) { - unsigned char b0 = data[0]; - if (!b0) - break; - unsigned char b1 = data[1]; - if (!b1) { - hash += b0; - hash ^= hash << 11; - hash += hash >> 17; - break; - } - hash += b0; - unsigned tmp = (b1 << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2; - hash += hash >> 11; - } - - // Force "avalanching" of final 127 bits. - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - hash &= 0x7fffffff; - - // 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. - if (hash == 0) - hash = 0x40000000; - - return hash; -} - -} // namespace WTF - -#endif // WTF_StringHashFunctions_h diff --git a/JavaScriptCore/wtf/StringHasher.h b/JavaScriptCore/wtf/StringHasher.h new file mode 100644 index 0000000..63ce74f --- /dev/null +++ b/JavaScriptCore/wtf/StringHasher.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2005, 2006, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * + * 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 WTF_StringHasher_h +#define WTF_StringHasher_h + +#include <wtf/unicode/Unicode.h> + +namespace WTF { + +// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's +static const unsigned stringHashingStartValue = 0x9e3779b9U; + +// Paul Hsieh's SuperFastHash +// http://www.azillionmonkeys.com/qed/hash.html +// char* data is interpreted as latin-encoded (zero extended to 16 bits). +class StringHasher { +public: + inline StringHasher() + : m_hash(stringHashingStartValue) + , m_hasPendingCharacter(false) + , m_pendingCharacter(0) + { + } + + inline void addCharacters(UChar a, UChar b) + { + ASSERT(!m_hasPendingCharacter); + addCharactersToHash(a, b); + } + + inline void addCharacter(UChar ch) + { + if (m_hasPendingCharacter) { + addCharactersToHash(m_pendingCharacter, ch); + m_hasPendingCharacter = false; + return; + } + + m_pendingCharacter = ch; + m_hasPendingCharacter = true; + } + + inline unsigned hash() const + { + unsigned result = m_hash; + + // Handle end case. + if (m_hasPendingCharacter) { + result += m_pendingCharacter; + result ^= result << 11; + result += result >> 17; + } + + // Force "avalanching" of final 31 bits. + result ^= result << 3; + result += result >> 5; + result ^= result << 2; + result += result >> 15; + result ^= result << 10; + + // First bit is used in UStringImpl for m_isIdentifier. + result &= 0x7fffffff; + + // 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. + if (!result) + return 0x40000000; + + return result; + } + + template<typename T, UChar Converter(T)> static inline unsigned createHash(const T* data, unsigned length) + { + StringHasher hasher; + bool rem = length & 1; + length >>= 1; + + while (length--) { + hasher.addCharacters(Converter(data[0]), Converter(data[1])); + data += 2; + } + + if (rem) + hasher.addCharacter(Converter(*data)); + + return hasher.hash(); + } + + template<typename T, UChar Converter(T)> static inline unsigned createHash(const T* data) + { + StringHasher hasher; + + while (true) { + UChar b0 = Converter(*data++); + if (!b0) + break; + UChar b1 = Converter(*data++); + if (!b1) { + hasher.addCharacter(b0); + break; + } + + hasher.addCharacters(b0, b1); + } + + return hasher.hash(); + } + + template<typename T> static inline unsigned createHash(const T* data, unsigned length) + { + return createHash<T, defaultCoverter>(data, length); + } + + template<typename T> static inline unsigned createHash(const T* data) + { + return createHash<T, defaultCoverter>(data); + } + + template<size_t length> static inline unsigned createBlobHash(const void* data) + { + COMPILE_ASSERT(!(length % 4), length_must_be_a_multible_of_four); + return createHash<UChar>(static_cast<const UChar*>(data), length / sizeof(UChar)); + } + +private: + static inline UChar defaultCoverter(UChar ch) + { + return ch; + } + + static inline UChar defaultCoverter(char ch) + { + return static_cast<unsigned char>(ch); + } + + inline void addCharactersToHash(UChar a, UChar b) + { + m_hash += a; + unsigned tmp = (b << 11) ^ m_hash; + m_hash = (m_hash << 16) ^ tmp; + m_hash += m_hash >> 11; + } + + unsigned m_hash; + bool m_hasPendingCharacter; + UChar m_pendingCharacter; +}; + +} // namespace WTF + +#endif // WTF_StringHasher_h diff --git a/JavaScriptCore/wtf/TCPageMap.h b/JavaScriptCore/wtf/TCPageMap.h index 3f56c24..99bdc40 100644 --- a/JavaScriptCore/wtf/TCPageMap.h +++ b/JavaScriptCore/wtf/TCPageMap.h @@ -72,7 +72,7 @@ class TCMalloc_PageMap1 { // Ensure that the map contains initialized entries "x .. x+n-1". // Returns true if successful, false if we could not allocate memory. - bool Ensure(Number x, size_t n) { + bool Ensure(Number, size_t) { // Nothing to do since flat array was allocate at start return true; } diff --git a/JavaScriptCore/wtf/TCSpinLock.h b/JavaScriptCore/wtf/TCSpinLock.h index 8a73e13..81b7d0c 100644 --- a/JavaScriptCore/wtf/TCSpinLock.h +++ b/JavaScriptCore/wtf/TCSpinLock.h @@ -1,4 +1,5 @@ // Copyright (c) 2005, 2006, Google Inc. +// Copyright (c) 2010, Patrick Gansterer <paroga@paroga.com> // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -37,8 +38,6 @@ #include <time.h> /* For nanosleep() */ -#include <sched.h> /* For sched_yield() */ - #if HAVE(STDINT_H) #include <stdint.h> #elif HAVE(INTTYPES_H) @@ -52,6 +51,8 @@ #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> +#else +#include <sched.h> /* For sched_yield() */ #endif static void TCMalloc_SlowLock(volatile unsigned int* lockword); @@ -134,7 +135,12 @@ struct TCMalloc_SpinLock { #define SPINLOCK_INITIALIZER { 0 } static void TCMalloc_SlowLock(volatile unsigned int* lockword) { - sched_yield(); // Yield immediately since fast path failed +// Yield immediately since fast path failed +#if OS(WINDOWS) + Sleep(0); +#else + sched_yield(); +#endif while (true) { int r; #if COMPILER(GCC) @@ -189,6 +195,44 @@ static void TCMalloc_SlowLock(volatile unsigned int* lockword) { } } +#elif OS(WINDOWS) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +static void TCMalloc_SlowLock(LPLONG lockword); + +// The following is a struct so that it can be initialized at compile time +struct TCMalloc_SpinLock { + + inline void Lock() { + if (InterlockedExchange(&m_lockword, 1)) + TCMalloc_SlowLock(&m_lockword); + } + + inline void Unlock() { + InterlockedExchange(&m_lockword, 0); + } + + inline bool IsHeld() const { + return m_lockword != 0; + } + + inline void Init() { m_lockword = 0; } + + LONG m_lockword; +}; + +#define SPINLOCK_INITIALIZER { 0 } + +static void TCMalloc_SlowLock(LPLONG lockword) { + Sleep(0); // Yield immediately since fast path failed + while (InterlockedExchange(lockword, 1)) + Sleep(2); +} + #else #include <pthread.h> diff --git a/JavaScriptCore/wtf/TCSystemAlloc.cpp b/JavaScriptCore/wtf/TCSystemAlloc.cpp index 4d02919..0b7ecc9 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.cpp +++ b/JavaScriptCore/wtf/TCSystemAlloc.cpp @@ -34,10 +34,10 @@ #include "TCSystemAlloc.h" #include <algorithm> -#include <fcntl.h> #include "Assertions.h" #include "TCSpinLock.h" #include "UnusedParam.h" +#include "VMTags.h" #if HAVE(STDINT_H) #include <stdint.h> @@ -178,7 +178,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..33c6612 --- /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: + void deref() + { + if (derefBase()) + delete static_cast<T*>(this); + } + +protected: + ThreadSafeShared() + { + } +}; + +} // namespace WTF + +using WTF::ThreadSafeShared; + +#endif // ThreadSafeShared_h diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h index 7e5679f..93ed466 100644 --- a/JavaScriptCore/wtf/ThreadSpecific.h +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -47,13 +47,15 @@ #include <pthread.h> #elif PLATFORM(QT) #include <QThreadStorage> +#elif PLATFORM(GTK) +#include <glib.h> #elif OS(WINDOWS) #include <windows.h> #endif namespace WTF { -#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) // ThreadSpecificThreadExit should be called each time when a thread is detached. // This is done automatically for threads created with WTF::createThread. void ThreadSpecificThreadExit(); @@ -65,18 +67,23 @@ public: T* operator->(); operator T*(); T& operator*(); - ~ThreadSpecific(); private: -#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) friend void ThreadSpecificThreadExit(); #endif + + // Not implemented. It's technically possible to destroy a thread specific key, but one would need + // to make sure that all values have been destroyed already (usually, that all threads that used it + // have exited). It's unlikely that any user of this call will be in that situation - and having + // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly. + ~ThreadSpecific(); T* get(); void set(T*); void static destroy(void* ptr); -#if USE(PTHREADS) || PLATFORM(QT) || OS(WINDOWS) +#if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(GTK) || OS(WINDOWS) struct Data : Noncopyable { Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} #if PLATFORM(QT) @@ -85,7 +92,7 @@ private: T* value; ThreadSpecific<T>* owner; -#if !USE(PTHREADS) && !PLATFORM(QT) +#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) void (*destructor)(void*); #endif }; @@ -98,6 +105,8 @@ private: pthread_key_t m_key; #elif PLATFORM(QT) QThreadStorage<Data*> m_key; +#elif PLATFORM(GTK) + GStaticPrivate m_key; #elif OS(WINDOWS) int m_index; #endif @@ -112,11 +121,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ -} - -template<typename T> inline T* ThreadSpecific<T>::get() { return m_value; @@ -139,12 +143,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ - pthread_key_delete(m_key); // Does not invoke destructor functions. -} - -template<typename T> inline T* ThreadSpecific<T>::get() { Data* data = static_cast<Data*>(pthread_getspecific(m_key)); @@ -166,15 +164,32 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() +inline T* ThreadSpecific<T>::get() +{ + Data* data = static_cast<Data*>(m_key.localData()); + return data ? data->value : 0; +} + +template<typename T> +inline void ThreadSpecific<T>::set(T* ptr) { - // Does not invoke destructor functions. QThreadStorage will do it + ASSERT(!get()); + Data* data = new Data(ptr, this); + m_key.setLocalData(data); +} + +#elif PLATFORM(GTK) + +template<typename T> +inline ThreadSpecific<T>::ThreadSpecific() +{ + g_static_private_init(&m_key); } template<typename T> inline T* ThreadSpecific<T>::get() { - Data* data = static_cast<Data*>(m_key.localData()); + Data* data = static_cast<Data*>(g_static_private_get(&m_key)); return data ? data->value : 0; } @@ -183,7 +198,7 @@ inline void ThreadSpecific<T>::set(T* ptr) { ASSERT(!get()); Data* data = new Data(ptr, this); - m_key.setLocalData(data); + g_static_private_set(&m_key, data, destroy); } #elif OS(WINDOWS) @@ -253,6 +268,9 @@ inline void ThreadSpecific<T>::destroy(void* ptr) // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor. // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it. pthread_setspecific(data->owner->m_key, ptr); +#elif PLATFORM(GTK) + // See comment as above + g_static_private_set(&data->owner->m_key, data, 0); #endif #if PLATFORM(QT) // See comment as above @@ -266,6 +284,8 @@ inline void ThreadSpecific<T>::destroy(void* ptr) pthread_setspecific(data->owner->m_key, 0); #elif PLATFORM(QT) // Do nothing here +#elif PLATFORM(GTK) + g_static_private_set(&data->owner->m_key, 0, 0); #elif OS(WINDOWS) TlsSetValue(tlsKeys()[data->owner->m_index], 0); #else @@ -285,7 +305,7 @@ inline ThreadSpecific<T>::operator T*() if (!ptr) { // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls // needs to access the value, to avoid recursion. - ptr = static_cast<T*>(fastMalloc(sizeof(T))); + ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T))); set(ptr); new (ptr) T; } diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h index 1599562..044365f 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,227 +98,21 @@ 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 yield(); 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; +using WTF::yield; #endif // Threading_h diff --git a/JavaScriptCore/wtf/ThreadingPrimitives.h b/JavaScriptCore/wtf/ThreadingPrimitives.h new file mode 100644 index 0000000..c11a6cb --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingPrimitives.h @@ -0,0 +1,155 @@ +/* + * 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" +#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..0017a6f 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -44,6 +44,7 @@ #if !COMPILER(MSVC) #include <limits.h> +#include <sched.h> #include <sys/time.h> #endif @@ -57,10 +58,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 +68,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() @@ -228,6 +222,11 @@ void detachThread(ThreadIdentifier threadID) pthread_detach(pthreadHandle); } +void yield() +{ + sched_yield(); +} + ThreadIdentifier currentThread() { ThreadIdentifier id = ThreadIdentifierData::identifier(); @@ -240,18 +239,15 @@ 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); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + + pthread_mutex_init(&m_mutex, &attr); + + pthread_mutexattr_destroy(&attr); } Mutex::~Mutex() diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp index 73c3f0c..a29fbbb 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() @@ -270,14 +266,14 @@ void detachThread(ThreadIdentifier threadID) clearThreadHandleForIdentifier(threadID); } -ThreadIdentifier currentThread() +void yield() { - return static_cast<ThreadIdentifier>(GetCurrentThreadId()); + ::Sleep(1); } -bool isMainThread() +ThreadIdentifier currentThread() { - return currentThread() == mainThreadIdentifier; + return static_cast<ThreadIdentifier>(GetCurrentThreadId()); } Mutex::Mutex() diff --git a/JavaScriptCore/wtf/TypeTraits.cpp b/JavaScriptCore/wtf/TypeTraits.cpp index 9e51ad0..afeaa5e 100644 --- a/JavaScriptCore/wtf/TypeTraits.cpp +++ b/JavaScriptCore/wtf/TypeTraits.cpp @@ -47,6 +47,11 @@ COMPILE_ASSERT(!IsInteger<volatile char*>::value, WTF_IsInteger_volatile_char_po COMPILE_ASSERT(!IsInteger<double>::value, WTF_IsInteger_double_false); COMPILE_ASSERT(!IsInteger<float>::value, WTF_IsInteger_float_false); +COMPILE_ASSERT(IsFloatingPoint<float>::value, WTF_IsFloatingPoint_float_true); +COMPILE_ASSERT(IsFloatingPoint<double>::value, WTF_IsFloatingPoint_double_true); +COMPILE_ASSERT(IsFloatingPoint<long double>::value, WTF_IsFloatingPoint_long_double_true); +COMPILE_ASSERT(!IsFloatingPoint<int>::value, WTF_IsFloatingPoint_int_false); + COMPILE_ASSERT(IsPod<bool>::value, WTF_IsPod_bool_true); COMPILE_ASSERT(IsPod<char>::value, WTF_IsPod_char_true); COMPILE_ASSERT(IsPod<signed char>::value, WTF_IsPod_signed_char_true); @@ -131,4 +136,7 @@ COMPILE_ASSERT((IsSameType<int, RemovePointer<int>::Type>::value), WTF_Test_Remo COMPILE_ASSERT((IsSameType<int, RemovePointer<int*>::Type>::value), WTF_Test_RemovePointer_int_pointer); COMPILE_ASSERT((!IsSameType<int, RemovePointer<int**>::Type>::value), WTF_Test_RemovePointer_int_pointer_pointer); +COMPILE_ASSERT((IsSameType<int, RemoveReference<int>::Type>::value), WTF_Test_RemoveReference_int); +COMPILE_ASSERT((IsSameType<int, RemoveReference<int&>::Type>::value), WTF_Test_RemoveReference_int_reference); + } // namespace WTF diff --git a/JavaScriptCore/wtf/TypeTraits.h b/JavaScriptCore/wtf/TypeTraits.h index 62dbc49..44103cd 100644 --- a/JavaScriptCore/wtf/TypeTraits.h +++ b/JavaScriptCore/wtf/TypeTraits.h @@ -39,6 +39,7 @@ namespace WTF { // IsSameType<T, U>::value // // RemovePointer<T>::Type + // RemoveReference<T>::Type // RemoveConst<T>::Type // RemoveVolatile<T>::Type // RemoveConstVolatile<T>::Type @@ -62,12 +63,16 @@ namespace WTF { template<> struct IsInteger<wchar_t> { static const bool value = true; }; #endif + template<typename T> struct IsFloatingPoint { static const bool value = false; }; + template<> struct IsFloatingPoint<float> { static const bool value = true; }; + template<> struct IsFloatingPoint<double> { static const bool value = true; }; + template<> struct IsFloatingPoint<long double> { static const bool value = true; }; + + template<typename T> struct IsArithmetic { static const bool value = IsInteger<T>::value || IsFloatingPoint<T>::value; }; + // IsPod is misnamed as it doesn't cover all plain old data (pod) types. // Specifically, it doesn't allow for enums or for structs. - template <typename T> struct IsPod { static const bool value = IsInteger<T>::value; }; - template <> struct IsPod<float> { static const bool value = true; }; - template <> struct IsPod<double> { static const bool value = true; }; - template <> struct IsPod<long double> { static const bool value = true; }; + template <typename T> struct IsPod { static const bool value = IsArithmetic<T>::value; }; template <typename P> struct IsPod<P*> { static const bool value = true; }; template<typename T> class IsConvertibleToInteger { @@ -166,6 +171,14 @@ namespace WTF { typedef T Type; }; + template <typename T> struct RemoveReference { + typedef T Type; + }; + + template <typename T> struct RemoveReference<T&> { + typedef T Type; + }; + #if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) // GCC's libstdc++ 20070724 and later supports C++ TR1 type_traits in the std namespace. diff --git a/JavaScriptCore/wtf/UnusedParam.h b/JavaScriptCore/wtf/UnusedParam.h index 996f5c8..6ff6fd8 100644 --- a/JavaScriptCore/wtf/UnusedParam.h +++ b/JavaScriptCore/wtf/UnusedParam.h @@ -24,6 +24,14 @@ /* don't use this for C++, it should only be used in plain C files or ObjC methods, where leaving off the parameter name is not allowed. */ -#define UNUSED_PARAM(x) (void)x +#include "Platform.h" + +#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +template<typename T> +inline void unusedParam(T& x) { (void)x; } +#define UNUSED_PARAM(variable) unusedParam(variable) +#else +#define UNUSED_PARAM(variable) (void)variable +#endif #endif /* WTF_UnusedParam_h */ 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..f73793f 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -24,6 +24,7 @@ #include "FastAllocBase.h" #include "Noncopyable.h" #include "NotFound.h" +#include "StdLibExtras.h" #include "ValueCheck.h" #include "VectorTraits.h" #include <limits> @@ -49,7 +50,7 @@ namespace WTF { #error WTF_ALIGN macros need alignment control. #endif - #if COMPILER(GCC) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) + #if COMPILER(GCC) && !COMPILER(INTEL) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) typedef char __attribute__((__may_alias__)) AlignedBufferChar; #else typedef char AlignedBufferChar; @@ -286,6 +287,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 +376,7 @@ namespace WTF { void restoreInlineBufferIfNeeded() { } using Base::allocateBuffer; + using Base::tryAllocateBuffer; using Base::deallocateBuffer; using Base::buffer; @@ -405,6 +421,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()) @@ -457,7 +482,7 @@ namespace WTF { using Base::m_capacity; static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); - T* inlineBuffer() { return reinterpret_cast<T*>(m_inlineBuffer.buffer); } + T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); } AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; }; @@ -533,11 +558,13 @@ namespace WTF { const T& last() const { return at(size() - 1); } template<typename U> size_t find(const U&) const; + template<typename U> size_t reverseFind(const U&) const; void shrink(size_t size); 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 +575,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 +620,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; @@ -658,6 +688,12 @@ namespace WTF { return *this; } +// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last +#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL + if (!begin()) + return *this; +#endif + std::copy(other.begin(), other.begin() + size(), begin()); TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); m_size = other.size(); @@ -665,13 +701,17 @@ namespace WTF { return *this; } + inline bool typelessPointersAreEqual(const void* a, const void* b) { return a == b; } + template<typename T, size_t inlineCapacity> template<size_t otherCapacity> Vector<T, inlineCapacity>& Vector<T, inlineCapacity>::operator=(const Vector<T, otherCapacity>& other) { - if (&other == this) - return *this; - + // If the inline capacities match, we should call the more specific + // template. If the inline capacities don't match, the two objects + // shouldn't be allocated the same address. + ASSERT(!typelessPointersAreEqual(&other, this)); + if (size() > other.size()) shrink(other.size()); else if (other.size() > capacity()) { @@ -681,6 +721,12 @@ namespace WTF { return *this; } +// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last +#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL + if (!begin()) + return *this; +#endif + std::copy(other.begin(), other.begin() + size(), begin()); TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); m_size = other.size(); @@ -700,6 +746,18 @@ namespace WTF { } template<typename T, size_t inlineCapacity> + template<typename U> + size_t Vector<T, inlineCapacity>::reverseFind(const U& value) const + { + for (size_t i = 1; i <= size(); ++i) { + const size_t index = size() - i; + if (at(index) == value) + return index; + } + return notFound; + } + + template<typename T, size_t inlineCapacity> void Vector<T, inlineCapacity>::fill(const T& val, size_t newSize) { if (size() > newSize) @@ -742,6 +800,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 +875,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 +941,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 +969,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/Vector3.h b/JavaScriptCore/wtf/Vector3.h index 3c40b61..1850929 100644 --- a/JavaScriptCore/wtf/Vector3.h +++ b/JavaScriptCore/wtf/Vector3.h @@ -26,12 +26,12 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Vector3_h -#define Vector3_h +#ifndef WTF_Vector3_h +#define WTF_Vector3_h #include <math.h> -namespace WebCore { +namespace WTF { class Vector3 { public: @@ -133,6 +133,6 @@ inline double distance(const Vector3& v1, const Vector3& v2) return (v1 - v2).abs(); } -} // WebCore +} // WTF -#endif // Vector3_h +#endif // WTF_Vector3_h 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..702baed --- /dev/null +++ b/JavaScriptCore/wtf/WTFThreadData.cpp @@ -0,0 +1,59 @@ +/* + * 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 +{ + char sample = 0; + m_approximatedStackStart = &sample; +} + +WTFThreadData::~WTFThreadData() +{ + if (m_atomicStringTableDestructor) + m_atomicStringTableDestructor(m_atomicStringTable); +#if USE(JSC) + delete m_defaultIdentifierTable; +#endif +} + +} diff --git a/JavaScriptCore/wtf/WTFThreadData.h b/JavaScriptCore/wtf/WTFThreadData.h new file mode 100644 index 0000000..5019c33 --- /dev/null +++ b/JavaScriptCore/wtf/WTFThreadData.h @@ -0,0 +1,168 @@ +/* + * 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 + +#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); + + bool remove(StringImpl* r) + { + HashSet<StringImpl*>::iterator iter = m_table.find(r); + if (iter == m_table.end()) + return false; + m_table.remove(iter); + return true; + } + + LiteralIdentifierTable& literalTable() { return m_literalTable; } + +private: + HashSet<StringImpl*> m_table; + LiteralIdentifierTable m_literalTable; +}; + +} +#endif + +namespace WTF { + +class AtomicStringTable; + +typedef void (*AtomicStringTableDestructor)(AtomicStringTable*); + +class WTFThreadData : public Noncopyable { +public: + WTFThreadData(); + ~WTFThreadData(); + + AtomicStringTable* atomicStringTable() + { + return m_atomicStringTable; + } + +#if USE(JSC) + 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 + + char* approximatedStackStart() const + { + return m_approximatedStackStart; + } + +private: + 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 AtomicStringTable; + + char* m_approximatedStackStart; +}; + +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..ce10fc3 100644 --- a/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp +++ b/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp @@ -1,51 +1,81 @@ /* - * 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> +#include <AEEIMemGroup.h> +#include <AEEIMemSpace.h> +#include <AEENet.h> +#include <AEESSL.h> #include <AEEStdLib.h> 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) +void deleteOwnedPtr(ISSL* ptr) +{ + if (ptr) + ISSL_Release(ptr); +} + +void deleteOwnedPtr(IMemGroup* ptr) { - FREEIF(ptr); + if (ptr) + IMemGroup_Release(ptr); } -} // namespace WTF +void deleteOwnedPtr(IMemSpace* ptr) +{ + if (ptr) + IMemSpace_Release(ptr); +} + +void deleteOwnedPtr(ISocket* ptr) +{ + if (ptr) + ISOCKET_Release(ptr); +} + +} 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/RefPtrBrew.h b/JavaScriptCore/wtf/brew/RefPtrBrew.h new file mode 100644 index 0000000..7fb0b7c --- /dev/null +++ b/JavaScriptCore/wtf/brew/RefPtrBrew.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2009 Martin Robinson + * 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 RefPtrBrew_h +#define RefPtrBrew_h + +#include "AlwaysInline.h" +#include "PlatformRefPtr.h" +#include <AEEIBase.h> +#include <algorithm> + +namespace WTF { + +// All Brew MP classes are derived from either IBase or IQI. +// Technically, IBase and IQI are different types. However, it is +// okay to cast both types to IBase because they have AddRef and Release +// in the same method vtable slots. +template <typename T> inline T* refPlatformPtr(T* ptr) +{ + if (ptr) + IBase_AddRef(reinterpret_cast<IBase*>(ptr)); + return ptr; +} + +template <typename T> inline void derefPlatformPtr(T* ptr) +{ + if (ptr) + IBase_Release(reinterpret_cast<IBase*>(ptr)); +} + +} // namespace WTF + +#endif // RefPtrBrew_h diff --git a/JavaScriptCore/wtf/brew/ShellBrew.h b/JavaScriptCore/wtf/brew/ShellBrew.h new file mode 100644 index 0000000..faccc75 --- /dev/null +++ b/JavaScriptCore/wtf/brew/ShellBrew.h @@ -0,0 +1,70 @@ +/* + * 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> +#include <wtf/PlatformRefPtr.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; +} + +template <typename T> +static inline PlatformRefPtr<T> createRefPtrInstance(AEECLSID cls) +{ + T* instance = 0; + + IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell; + ISHELL_CreateInstance(shell, cls, reinterpret_cast<void**>(&instance)); + ASSERT(instance); + + return adoptPlatformRef(instance); +} + +} // namespace WTF + +using WTF::createInstance; +using WTF::createRefPtrInstance; + +#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/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp index e63be90..c89c036 100644 --- a/JavaScriptCore/wtf/dtoa.cpp +++ b/JavaScriptCore/wtf/dtoa.cpp @@ -3,7 +3,7 @@ * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice @@ -18,14 +18,8 @@ * ***************************************************************/ -/* Please send bug reports to - David M. Gay - Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-0636 - U.S.A. - dmg@bell-labs.com - */ +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision @@ -50,7 +44,7 @@ * * Modifications: * - * 1. We only require IEEE. + * 1. We only require IEEE double-precision arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too @@ -67,91 +61,26 @@ * for 0 <= k <= 22). */ -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define USE_LONG_LONG on machines that have a "long long" - * integer type (of >= 64 bits), and performance testing shows that - * it is faster than 32-bit fallback (which is often not the case - * on 32-bit machines). On such machines, you can #define Just_16 - * to store 16 bits per 32-bit int32_t when doing high-precision integer - * arithmetic. Whether this speeds things up or slows things down - * depends on the machine and the number being converted. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define INFNAN_CHECK on IEEE systems to cause strtod to check for - * Infinity and NaN (case insensitively). On some systems (e.g., - * some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtod also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the 52 fraction bits of the resulting NaN; if there are two - * or more strings of hex digits, the first is for the high 20 bits, - * the second and subsequent for the low 32 bits, with intervening - * white space ignored; but if this results in none of the 52 - * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 - * and NAN_WORD1 are used instead. - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define YES_ALIAS to permit aliasing certain double values with - * arrays of ULongs. This leads to slightly better code with - * some compilers and was always used prior to 19990916, but it - * is not strictly legal and can cause trouble with aggressively - * optimizing compilers (e.g., gcc 2.95.1 under -O2). - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - */ - #include "config.h" #include "dtoa.h" #if HAVE(ERRNO_H) #include <errno.h> -#else -#define NO_ERRNO #endif +#include <float.h> #include <math.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <wtf/AlwaysInline.h> #include <wtf/Assertions.h> +#include <wtf/DecimalNumber.h> #include <wtf/FastMalloc.h> #include <wtf/MathExtras.h> -#include <wtf/Vector.h> #include <wtf/Threading.h> - -#include <stdio.h> +#include <wtf/UnusedParam.h> +#include <wtf/Vector.h> #if COMPILER(MSVC) #pragma warning(disable: 4244) @@ -159,58 +88,42 @@ #pragma warning(disable: 4554) #endif -#if CPU(BIG_ENDIAN) -#define IEEE_MC68k -#elif CPU(MIDDLE_ENDIAN) -#define IEEE_ARM -#else -#define IEEE_8087 -#endif - -#define INFNAN_CHECK -#define No_Hex_NaN - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1 -Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined. -#endif - namespace WTF { #if ENABLE(JSC_MULTIPLE_THREADS) Mutex* s_dtoaP5Mutex; #endif -typedef union { double d; uint32_t L[2]; } U; +typedef union { + double d; + uint32_t L[2]; +} U; -#ifdef YES_ALIAS -#define dval(x) x -#ifdef IEEE_8087 -#define word0(x) ((uint32_t*)&x)[1] -#define word1(x) ((uint32_t*)&x)[0] -#else -#define word0(x) ((uint32_t*)&x)[0] -#define word1(x) ((uint32_t*)&x)[1] -#endif +#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] #else -#ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] #endif #define dval(x) (x)->d -#endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + * *p++ = high << 16 | low & 0xffff; */ -#if defined(IEEE_8087) || defined(IEEE_ARM) -#define Storeinc(a,b,c) (((unsigned short*)a)[1] = (unsigned short)b, ((unsigned short*)a)[0] = (unsigned short)c, a++) +static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low) +{ + uint16_t* p16 = reinterpret_cast<uint16_t*>(p); +#if CPU(BIG_ENDIAN) + p16[0] = high; + p16[1] = low; #else -#define Storeinc(a,b,c) (((unsigned short*)a)[0] = (unsigned short)b, ((unsigned short*)a)[1] = (unsigned short)c, a++) + p16[1] = high; + p16[0] = low; #endif + return p + 1; +} #define Exp_shift 20 #define Exp_shift1 20 @@ -237,51 +150,18 @@ typedef union { double d; uint32_t L[2]; } U; #define Quick_max 14 #define Int_max 14 -#if !defined(NO_IEEE_Scale) -#undef Avoid_Underflow -#define Avoid_Underflow -#endif - -#if !defined(Flt_Rounds) -#if defined(FLT_ROUNDS) -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - - -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b +#define rounded_product(a, b) a *= b +#define rounded_quotient(a, b) a /= b #define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) #define Big1 0xffffffff - -// FIXME: we should remove non-Pack_32 mode since it is unused and unmaintained -#ifndef Pack_32 -#define Pack_32 -#endif - #if CPU(PPC64) || CPU(X86_64) // FIXME: should we enable this on all 64-bit CPUs? // 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware. #define USE_LONG_LONG #endif -#ifndef USE_LONG_LONG -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per int32_t. - */ -#endif -#endif - -#define Kmax 15 - struct BigInt { BigInt() : sign(0) { } int sign; @@ -291,7 +171,7 @@ struct BigInt { sign = 0; m_words.clear(); } - + size_t size() const { return m_words.size(); @@ -301,7 +181,7 @@ struct BigInt { { m_words.resize(s); } - + uint32_t* words() { return m_words.data(); @@ -311,12 +191,12 @@ struct BigInt { { return m_words.data(); } - + void append(uint32_t w) { m_words.append(w); } - + Vector<uint32_t, 16> m_words; }; @@ -338,17 +218,11 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ carry = y >> 32; *x++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 uint32_t xi = *x; uint32_t y = (xi & 0xffff) * m + carry; uint32_t z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); -#else - uint32_t y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif #endif } while (++i < wds); @@ -358,20 +232,9 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ static void s2b(BigInt& b, const char* s, int nd0, int nd, uint32_t y9) { - int k; - int32_t y; - int32_t x = (nd + 8) / 9; - - for (k = 0, y = 1; x > y; y <<= 1, k++) { } -#ifdef Pack_32 b.sign = 0; b.resize(1); b.words()[0] = y9; -#else - b.sign = 0; - b.resize((b->x[1] = y9 >> 16) ? 2 : 1); - b.words()[0] = y9 & 0xffff; -#endif int i = 9; if (9 < nd0) { @@ -414,7 +277,7 @@ static int hi0bits(uint32_t x) return k; } -static int lo0bits (uint32_t* y) +static int lo0bits(uint32_t* y) { int k; uint32_t x = *y; @@ -449,7 +312,7 @@ static int lo0bits (uint32_t* y) if (!(x & 1)) { k++; x >>= 1; - if (!x & 1) + if (!x) return 32; } *y = x; @@ -469,8 +332,13 @@ static void mult(BigInt& aRef, const BigInt& bRef) const BigInt* b = &bRef; BigInt c; int wa, wb, wc; - const uint32_t *x = 0, *xa, *xb, *xae, *xbe; - uint32_t *xc, *xc0; + const uint32_t* x = 0; + const uint32_t* xa; + const uint32_t* xb; + const uint32_t* xae; + const uint32_t* xbe; + uint32_t* xc; + uint32_t* xc0; uint32_t y; #ifdef USE_LONG_LONG unsigned long long carry, z; @@ -483,7 +351,7 @@ static void mult(BigInt& aRef, const BigInt& bRef) a = b; b = tmp; } - + wa = a->size(); wb = b->size(); wc = wa + wb; @@ -511,7 +379,6 @@ static void mult(BigInt& aRef, const BigInt& bRef) } } #else -#ifdef Pack_32 for (; xb < xbe; xb++, xc0++) { if ((y = *xb & 0xffff)) { x = xa; @@ -522,7 +389,7 @@ static void mult(BigInt& aRef, const BigInt& bRef) carry = z >> 16; uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; - Storeinc(xc, z2, z); + xc = storeInc(xc, z2, z); } while (x < xae); *xc = carry; } @@ -534,28 +401,13 @@ static void mult(BigInt& aRef, const BigInt& bRef) do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; - Storeinc(xc, z, z2); + xc = storeInc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while (x < xae); *xc = z2; } } -#else - for(; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } while (x < xae); - *xc = carry; - } - } -#endif #endif for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { } c.resize(wc); @@ -566,9 +418,9 @@ struct P5Node : Noncopyable { BigInt val; P5Node* next; }; - + static P5Node* p5s; -static int p5s_count; +static int p5sCount; static ALWAYS_INLINE void pow5mult(BigInt& b, int k) { @@ -591,14 +443,14 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) i2b(p5->val, 625); p5->next = 0; p5s = p5; - p5s_count = 1; + p5sCount = 1; } - int p5s_count_local = p5s_count; + int p5sCountLocal = p5sCount; #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex->unlock(); #endif - int p5s_used = 0; + int p5sUsed = 0; for (;;) { if (k & 1) @@ -607,20 +459,20 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) if (!(k >>= 1)) break; - if (++p5s_used == p5s_count_local) { + if (++p5sUsed == p5sCountLocal) { #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex->lock(); #endif - if (p5s_used == p5s_count) { + if (p5sUsed == p5sCount) { ASSERT(!p5->next); p5->next = new P5Node; p5->next->next = 0; p5->next->val = p5->val; mult(p5->next->val, p5->next->val); - ++p5s_count; + ++p5sCount; } - - p5s_count_local = p5s_count; + + p5sCountLocal = p5sCount; #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex->unlock(); #endif @@ -631,11 +483,7 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) static ALWAYS_INLINE void lshift(BigInt& b, int k) { -#ifdef Pack_32 int n = k >> 5; -#else - int n = k >> 4; -#endif int origSize = b.size(); int n1 = n + origSize + 1; @@ -649,7 +497,6 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) uint32_t* dstStart = b.words(); const uint32_t* src = srcStart + origSize - 1; uint32_t* dst = dstStart + n1 - 1; -#ifdef Pack_32 if (k) { uint32_t hiSubword = 0; int s = 32 - k; @@ -660,21 +507,8 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) *dst = hiSubword; ASSERT(dst == dstStart + n); - b.resize(origSize + n + (b.words()[n1 - 1] != 0)); + b.resize(origSize + n + !!b.words()[n1 - 1]); } -#else - if (k &= 0xf) { - uint32_t hiSubword = 0; - int s = 16 - k; - for (; src >= srcStart; --src) { - *dst-- = hiSubword | *src >> s; - hiSubword = (*src << k) & 0xffff; - } - *dst = hiSubword; - ASSERT(dst == dstStart + n); - result->wds = b->wds + n + (result->x[n1 - 1] != 0); - } - #endif else { do { *--dst = *src--; @@ -715,7 +549,7 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef const BigInt* a = &aRef; const BigInt* b = &bRef; int i, wa, wb; - uint32_t *xc; + uint32_t* xc; i = cmp(*a, *b); if (!i) { @@ -756,34 +590,21 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef } #else uint32_t borrow = 0; -#ifdef Pack_32 do { uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); + xc = storeInc(xc, z, y); } while (xb < xbe); while (xa < xae) { uint32_t y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; uint32_t z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - uint32_t y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - uint32_t y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; + xc = storeInc(xc, z, y); } #endif -#endif while (!*--xc) wa--; c.resize(wa); @@ -795,28 +616,8 @@ static double ulp(U *x) U u; L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif word0(&u) = L; word1(&u) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&u) = 0x80000 >> L; - word1(&u) = 0; - } else { - word0(&u) = 0; - L -= Exp_shift; - word1(&u) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif return dval(&u); } @@ -839,12 +640,11 @@ static double b2d(const BigInt& a, int* e) ASSERT(y); k = hi0bits(y); *e = 32 - k; -#ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | (y >> (Ebits - k)); w = xa > xa0 ? *--xa : 0; d1 = (y << (32 - Ebits + k)) | (w >> (Ebits - k)); - goto ret_d; + goto returnD; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { @@ -855,23 +655,7 @@ static double b2d(const BigInt& a, int* e) d0 = Exp_1 | y; d1 = z; } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif -ret_d: +returnD: #undef d0 #undef d1 return dval(&d); @@ -880,105 +664,46 @@ ret_d: static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits) { int de, k; - uint32_t *x, y, z; -#ifndef Sudden_Underflow + uint32_t* x; + uint32_t y, z; int i; -#endif #define d0 word0(d) #define d1 word1(d) b.sign = 0; -#ifdef Pack_32 b.resize(1); -#else - b.resize(2); -#endif x = b.words(); z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#else if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; -#endif -#ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(&y))) { x[0] = y | (z << (32 - k)); z >>= k; } else x[0] = y; - if (z) { - b.resize(2); - x[1] = z; - } + if (z) { + b.resize(2); + x[1] = z; + } -#ifndef Sudden_Underflow i = b.size(); -#endif } else { k = lo0bits(&z); x[0] = z; -#ifndef Sudden_Underflow i = 1; -#endif b.resize(1); k += 32; } -#else - if ((y = d1)) { - if ((k = lo0bits(&y))) { - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k + 16; - i = 3; - } - } else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } else { - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } while (!x[i]) - --i; - b->resize(i + 1); -#endif -#ifndef Sudden_Underflow if (de) { -#endif *e = de - Bias - (P - 1) + k; *bits = P - k; -#ifndef Sudden_Underflow } else { *e = de - Bias - (P - 1) + 1 + k; -#ifdef Pack_32 *bits = (32 * i) - hi0bits(x[i - 1]); -#else - *bits = (i + 2) * 16 - hi0bits(x[i]); -#endif } -#endif } #undef d0 #undef d1 @@ -990,11 +715,7 @@ static double ratio(const BigInt& a, const BigInt& b) dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); -#ifdef Pack_32 k = ka - kb + 32 * (a.size() - b.size()); -#else - k = ka - kb + 16 * (a.size() - b.size()); -#endif if (k > 0) word0(&da) += k * Exp_msk1; else { @@ -1005,19 +726,15 @@ static double ratio(const BigInt& a, const BigInt& b) } static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 }; static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992. * 9007199254740992.e-256 - /* = 2^106 * 1e-53 */ -#else - 1e-256 -#endif + 9007199254740992. * 9007199254740992.e-256 + /* = 2^106 * 1e-256 */ }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ @@ -1025,118 +742,42 @@ static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #define Scale_Bit 0x10 #define n_bigtens 5 -#if defined(INFNAN_CHECK) - -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - -static int match(const char** sp, const char* t) -{ - int c, d; - const char* s = *sp; - - while ((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; -} - -#ifndef No_Hex_NaN -static void hexnan(U* rvp, const char** sp) -{ - uint32_t c, x[2]; - const char* s; - int havedig, udx0, xshift; - - x[0] = x[1] = 0; - havedig = xshift = 0; - udx0 = 1; - s = *sp; - while ((c = *(const unsigned char*)++s)) { - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c += 10 - 'a'; - else if (c >= 'A' && c <= 'F') - c += 10 - 'A'; - else if (c <= ' ') { - if (udx0 && havedig) { - udx0 = 0; - xshift = 1; - } - continue; - } else if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } else - return; /* invalid form: don't change *sp */ - havedig = 1; - if (xshift) { - xshift = 0; - x[0] = x[1]; - x[1] = 0; - } - if (udx0) - x[0] = (x[0] << 4) | (x[1] >> 28); - x[1] = (x[1] << 4) | c; - } - if ((x[0] &= 0xfffff) || x[1]) { - word0(rvp) = Exp_mask | x[0]; - word1(rvp) = x[1]; - } -} -#endif /*No_Hex_NaN*/ -#endif /* INFNAN_CHECK */ - double strtod(const char* s00, char** se) { -#ifdef Avoid_Underflow int scale; -#endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1; double aadj, aadj1; U aadj2, adj, rv, rv0; int32_t L; uint32_t y, z; BigInt bb, bb1, bd, bd0, bs, delta; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif sign = nz0 = nz = 0; dval(&rv) = 0; - for (s = s00; ; s++) + for (s = s00; ; s++) { switch (*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; } + } break2: if (*s == '0') { nz0 = 1; @@ -1161,12 +802,12 @@ break2: s0 = s; nf += nz; nz = 0; - goto have_dig; + goto haveDig; } - goto dig_done; + goto digDone; } for (; c >= '0' && c <= '9'; c = *++s) { -have_dig: +haveDig: nz++; if (c -= '0') { nf += nz; @@ -1183,19 +824,18 @@ have_dig: } } } -dig_done: +digDone: e = 0; if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { + if (!nd && !nz && !nz0) goto ret0; - } s00 = s; esign = 0; switch (c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; + case '-': + esign = 1; + case '+': + c = *++s; } if (c >= '0' && c <= '9') { while (c == '0') @@ -1221,33 +861,6 @@ dig_done: } if (!nd) { if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - hexnan(&rv, &s); -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ ret0: s = s00; sign = 0; @@ -1265,14 +878,9 @@ ret0: nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif + if (k > 9) dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - if (nd <= DBL_DIG && Flt_Rounds == 1) { + if (nd <= DBL_DIG) { if (!e) goto ret; if (e > 0) { @@ -1290,24 +898,14 @@ ret0: /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { + } else if (e >= -Ten_pmax) { /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } -#endif } e1 += nd - k; -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow scale = 0; -#endif /* Get starting approximation = rv * 10**e1 */ @@ -1317,17 +915,12 @@ ret0: if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif /* Can't trust HUGE_VAL */ word0(&rv) = Exp_mask; word1(&rv) = 0; -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif goto ret; } e1 >>= 4; @@ -1354,50 +947,30 @@ ovfl: if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; -#ifdef Avoid_Underflow if (e1 & Scale_Bit) scale = 2 * P; for (j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (scale && (j = (2 * P) + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ + /* scaled rv is denormal; clear j low bits */ if (j >= 32) { word1(&rv) = 0; if (j >= 53) - word0(&rv) = (P + 2) * Exp_msk1; + word0(&rv) = (P + 2) * Exp_msk1; else - word0(&rv) &= 0xffffffff << (j - 32); + word0(&rv) &= 0xffffffff << (j - 32); } else word1(&rv) &= 0xffffffff << j; } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2. * dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif if (!dval(&rv)) { undfl: dval(&rv) = 0.; -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif goto ret; } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif } } @@ -1424,30 +997,15 @@ undfl: else bd2 -= bbe; bs2 = bb2; -#ifdef Avoid_Underflow j = bbe - scale; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow - j = P + 1 - bbbits; -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; -#ifdef Avoid_Underflow bd2 += scale; -#endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; @@ -1478,62 +1036,36 @@ undfl: * special case of mantissa a power of two. */ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef Avoid_Underflow || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif ) { -#ifdef SET_INEXACT - if (!delta->words()[0] && delta->size() <= 1) - inexact = 0; -#endif break; } if (!delta.words()[0] && delta.size() <= 1) { /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif break; } lshift(delta, Log2P); if (cmp(delta, bs) > 0) - goto drop_down; + goto dropDown; break; } - if (i == 0) { + if (!i) { /* exactly half-way between */ if (dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( -#ifdef Avoid_Underflow (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) ? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) : -#endif 0xffffffff)) { /*boundary case -- increment exponent*/ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1; word1(&rv) = 0; -#ifdef Avoid_Underflow dsign = 0; -#endif break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { -drop_down: +dropDown: /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow if (scale) { L = word0(&rv) & Exp_mask; if (L <= (2 * P + 1) * Exp_msk1) { @@ -1545,9 +1077,7 @@ drop_down: goto undfl; } } -#endif /*Avoid_Underflow*/ L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; break; @@ -1558,24 +1088,18 @@ drop_down: dval(&rv) += ulp(&rv); else { dval(&rv) -= ulp(&rv); -#ifndef Sudden_Underflow if (!dval(&rv)) goto undfl; -#endif } -#ifdef Avoid_Underflow dsign = 1 - dsign; -#endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow if (word1(&rv) == Tiny1 && !word0(&rv)) goto undfl; -#endif aadj = 1.; aadj1 = -1.; } else { @@ -1591,19 +1115,6 @@ drop_down: } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch (Rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (Flt_Rounds == 0) - aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ } y = word0(&rv) & Exp_mask; @@ -1620,10 +1131,9 @@ drop_down: word0(&rv) = Big0; word1(&rv) = Big1; goto cont; - } else - word0(&rv) += P * Exp_msk1; + } + word0(&rv) += P * Exp_msk1; } else { -#ifdef Avoid_Underflow if (scale && y <= 2 * P * Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (uint32_t)aadj) <= 0) @@ -1637,51 +1147,9 @@ drop_down: } adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P * Exp_msk1; - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) - { - if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) - goto undfl; - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - else - word0(&rv) -= P * Exp_msk1; - } else { - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P - 1) * Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ } z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { + if (!scale && y == z) { /* Can we stop now? */ L = (int32_t)aadj; aadj -= L; @@ -1692,39 +1160,19 @@ drop_down: } else if (aadj < .4999999 / FLT_RADIX) break; } -#endif cont: - ; - } -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow + {} + } if (scale) { word0(&rv0) = Exp_1 - 2 * P * Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) /* try to avoid the bug of testing an 8087 register value */ - if (word0(&rv) == 0 && word1(&rv) == 0) + if (!word0(&rv) && !word1(&rv)) errno = ERANGE; #endif } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif ret: if (se) *se = const_cast<char*>(s); @@ -1734,15 +1182,17 @@ ret: static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) { size_t n; - uint32_t *bx, *bxe, q, *sx, *sxe; + uint32_t* bx; + uint32_t* bxe; + uint32_t q; + uint32_t* sx; + uint32_t* sxe; #ifdef USE_LONG_LONG unsigned long long borrow, carry, y, ys; #else uint32_t borrow, carry, y, ys; -#ifdef Pack_32 uint32_t si, z, zs; #endif -#endif ASSERT(b.size() <= 1 || b.words()[b.size() - 1]); ASSERT(S.size() <= 1 || S.words()[S.size() - 1]); @@ -1767,7 +1217,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); @@ -1776,14 +1225,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif + bx = storeInc(bx, z, y); #endif } while (sx <= sxe); if (!*bxe) { @@ -1807,7 +1249,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); @@ -1816,14 +1257,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif + bx = storeInc(bx, z, y); #endif } while (sx <= sxe); bx = b.words(); @@ -1840,7 +1274,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate @@ -1869,78 +1303,54 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the int32_t * calculation. + * + * Note: 'leftright' translates to 'generate shortest possible string'. */ - -void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char** rve) +template<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright> +void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut) { - /* - Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. + // Exactly one rounding mode must be specified. + ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1); + // roundingNone only allowed (only sensible?) with leftright set. + ASSERT(!roundingNone || leftright); - */ + ASSERT(!isnan(dd) && !isinf(dd)); int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; + j, j1, k, k0, k_check, m2, m5, s2, s5, + spec_case; int32_t L; -#ifndef Sudden_Underflow int denorm; uint32_t x; -#endif - BigInt b, b1, delta, mlo, mhi, S; + BigInt b, delta, mlo, mhi, S; U d2, eps, u; double ds; - char *s, *s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif + char* s; + char* s0; u.d = dd; - if (word0(&u) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&u) &= ~Sign_bit; /* clear sign bit */ - } else - *sign = 0; - if ((word0(&u) & Exp_mask) == Exp_mask) - { - /* Infinity or NaN */ - *decpt = 9999; - if (!word1(&u) && !(word0(&u) & 0xfffff)) { - strcpy(result, "Infinity"); - if (rve) - *rve = result + 8; - } else { - strcpy(result, "NaN"); - if (rve) - *rve = result + 3; - } - return; - } + /* Infinity or NaN */ + ASSERT((word0(&u) & Exp_mask) != Exp_mask); + + // JavaScript toString conversion treats -0 as 0. if (!dval(&u)) { - *decpt = 1; + signOut = false; + exponentOut = 0; + precisionOut = 1; result[0] = '0'; result[1] = '\0'; - if (rve) - *rve = result + 1; return; } -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif + if (word0(&u) & Sign_bit) { + signOut = true; + word0(&u) &= ~Sign_bit; // clear sign bit + } else + signOut = false; d2b(b, &u, &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); -#else if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) { -#endif dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; @@ -1968,7 +1378,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char */ i -= Bias; -#ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ @@ -1981,7 +1390,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char i -= (Bias + (P - 1) - 1) + 1; denorm = 1; } -#endif ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981); k = (int)ds; if (ds < 0. && ds != k) @@ -2010,22 +1418,27 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char s5 = 0; } -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ + if (roundingNone) { + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + } + if (roundingSignificantFigures) { + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + } + if (roundingDecimalPlaces) { + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } - leftright = 1; - ilim = ilim1 = -1; - i = 18; - ndigits = 0; s = s0 = result; - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - + if (ilim >= 0 && ilim <= Quick_max) { /* Try to get by with floating-point arithmetic. */ i = 0; @@ -2060,7 +1473,7 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char } if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) - goto fast_failed; + goto fastFailed; ilim = ilim1; k--; dval(&u) *= 10.; @@ -2068,17 +1481,16 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char } dval(&eps) = (ieps * dval(&u)) + 7.; word0(&eps) -= (P - 1) * Exp_msk1; - if (ilim == 0) { + if (!ilim) { S.clear(); mhi.clear(); dval(&u) -= 5.; if (dval(&u) > dval(&eps)) - goto one_digit; + goto oneDigit; if (dval(&u) < -dval(&eps)) - goto no_digits; - goto fast_failed; + goto noDigits; + goto fastFailed; } -#ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. @@ -2091,14 +1503,13 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char if (dval(&u) < dval(&eps)) goto ret; if (1. - dval(&u) < dval(&eps)) - goto bump_up; + goto bumpUp; if (++i >= ilim) break; dval(&eps) *= 10.; dval(&u) *= 10.; } } else { -#endif /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim - 1]; for (i = 1;; i++, dval(&u) *= 10.) { @@ -2108,8 +1519,8 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char *s++ = '0' + (int)L; if (i == ilim) { if (dval(&u) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&u) < 0.5 - dval(&eps)) { + goto bumpUp; + if (dval(&u) < 0.5 - dval(&eps)) { while (*--s == '0') { } s++; goto ret; @@ -2117,10 +1528,8 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char break; } } -#ifndef No_leftright } -#endif -fast_failed: +fastFailed: s = s0; dval(&u) = dval(&d2); k = k0; @@ -2136,30 +1545,20 @@ fast_failed: S.clear(); mhi.clear(); if (ilim < 0 || dval(&u) <= 5 * ds) - goto no_digits; - goto one_digit; + goto noDigits; + goto oneDigit; } for (i = 1;; i++, dval(&u) *= 10.) { L = (int32_t)(dval(&u) / ds); dval(&u) -= L * ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&u) < 0) { - L--; - dval(&u) += ds; - } -#endif *s++ = '0' + (int)L; if (!dval(&u)) { -#ifdef SET_INEXACT - inexact = 0; -#endif break; } if (i == ilim) { dval(&u) += dval(&u); if (dval(&u) > ds || (dval(&u) == ds && (L & 1))) { -bump_up: +bumpUp: while (*--s == '9') if (s == s0) { k++; @@ -2179,11 +1578,7 @@ bump_up: mhi.clear(); mlo.clear(); if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P - 1) - 1 + 1) : -#endif - 1 + P - bbits; + i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits; b2 += i; s2 += i; i2b(mhi, 1); @@ -2204,7 +1599,7 @@ bump_up: pow5mult(b, j); } else pow5mult(b, b5); - } + } i2b(S, 1); if (s5 > 0) pow5mult(S, s5); @@ -2212,11 +1607,7 @@ bump_up: /* Check for special case that d is a normalized power of 2. */ spec_case = 0; - if (!word1(&u) && !(word0(&u) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&u) & (Exp_mask & ~Exp_msk1) -#endif - ) { + if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) { /* The special case */ b2 += Log2P; s2 += Log2P; @@ -2230,13 +1621,8 @@ bump_up: * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ -#ifdef Pack_32 if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0x1f)) i = 32 - i; -#else - if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0xf)) - i = 16 - i; -#endif if (i > 4) { i -= 4; b2 += i; @@ -2253,7 +1639,7 @@ bump_up: if (s2 > 0) lshift(S, s2); if (k_check) { - if (cmp(b,S) < 0) { + if (cmp(b, S) < 0) { k--; multadd(b, 10, 0); /* we botched the k estimate */ if (leftright) @@ -2261,7 +1647,15 @@ bump_up: ilim = ilim1; } } - + if (ilim <= 0 && roundingDecimalPlaces) { + if (ilim < 0) + goto noDigits; + multadd(S, 5, 0); + // For IEEE-754 unbiased rounding this check should be <=, such that 0.5 would flush to zero. + if (cmp(b, S) < 0) + goto noDigits; + goto oneDigit; + } if (leftright) { if (m2 > 0) lshift(mhi, m2); @@ -2271,51 +1665,60 @@ bump_up: */ mlo = mhi; - if (spec_case) { - mhi = mlo; + if (spec_case) lshift(mhi, Log2P); - } for (i = 1;;i++) { - dig = quorem(b,S) + '0'; + dig = quorem(b, S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); diff(delta, S, mhi); j1 = delta.sign ? 1 : cmp(b, delta); - if (j1 == 0 && !(word1(&u) & 1)) { +#ifdef DTOA_ROUND_BIASED + if (j < 0 || !j) { +#else + // FIXME: ECMA-262 specifies that equidistant results round away from + // zero, which probably means we shouldn't be on the unbiased code path + // (the (word1(&u) & 1) clause is looking highly suspicious). I haven't + // yet understood this code well enough to make the call, but we should + // probably be enabling DTOA_ROUND_BIASED. I think the interesting corner + // case to understand is probably "Math.pow(0.5, 24).toString()". + // I believe this value is interesting because I think it is precisely + // representable in binary floating point, and its decimal representation + // has a single digit that Steele & White reduction can remove, with the + // value 5 (thus equidistant from the next numbers above and below). + // We produce the correct answer using either codepath, and I don't as + // yet understand why. :-) + if (!j1 && !(word1(&u) & 1)) { if (dig == '9') - goto round_9_up; + goto round9up; if (j > 0) dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif *s++ = dig; goto ret; } - if (j < 0 || (j == 0 && !(word1(&u) & 1))) { - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; + if (j < 0 || (!j && !(word1(&u) & 1))) { #endif - goto accept_dig; - } - if (j1 > 0) { + if ((b.words()[0] || b.size() > 1) && (j1 > 0)) { lshift(b, 1); j1 = cmp(b, S); - if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') - goto round_9_up; + // For IEEE-754 round-to-even, this check should be (j1 > 0 || (!j1 && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j1 >= 0) { + if (dig == '9') + goto round9up; + dig++; + } } -accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { if (dig == '9') { /* possible if i == 1 */ -round_9_up: +round9up: *s++ = '9'; goto roundoff; } @@ -2329,25 +1732,25 @@ round_9_up: multadd(mlo, 10, 0); multadd(mhi, 10, 0); } - } else + } else { for (i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif + *s++ = dig = quorem(b, S) + '0'; + if (!b.words()[0] && b.size() <= 1) goto ret; - } if (i >= ilim) break; multadd(b, 10, 0); } + } /* Round off last digit */ lshift(b, 1); j = cmp(b, S); - if (j > 0 || (j == 0 && (dig & 1))) { + // For IEEE-754 round-to-even, this check should be (j > 0 || (!j && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j >= 0) { roundoff: while (*--s == '9') if (s == s0) { @@ -2361,107 +1764,68 @@ roundoff: s++; } goto ret; -no_digits: - k = -1 - ndigits; - goto ret; -one_digit: +noDigits: + exponentOut = 0; + precisionOut = 1; + result[0] = '0'; + result[1] = '\0'; + return; +oneDigit: *s++ = '1'; k++; goto ret; ret: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&u) = Exp_1 + (70 << Exp_shift); - word1(&u) = 0; - dval(&u) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif + ASSERT(s > result); *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; + exponentOut = k; + precisionOut = s - result; } -static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size) +void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision) { - for (unsigned i = 0; i < size; ++i) - *next++ = *src++; + // flags are roundingNone, leftright. + dtoa<true, false, false, true>(result, dd, 0, sign, exponent, precision); } -void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength) +void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) { - ASSERT(buffer); + // flag is roundingSignificantFigures. + dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision); +} - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) { - append(buffer, "NaN", 3); - if (resultLength) - *resultLength = 3; - return; - } - // -0 -> "0" - if (!d) { - buffer[0] = '0'; - if (resultLength) - *resultLength = 1; - return; - } +void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) +{ + // flag is roundingDecimalPlaces. + dtoa<false, false, true, false>(result, dd, ndigits, sign, exponent, precision); +} - int decimalPoint; - int sign; +static ALWAYS_INLINE void copyAsciiToUTF16(UChar* next, const char* src, unsigned size) +{ + for (unsigned i = 0; i < size; ++i) + *next++ = *src++; +} - DtoaBuffer result; - char* resultEnd = 0; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd); - int length = resultEnd - result; - - char* next = buffer; - if (sign) - *next++ = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - *next++ = '0'; - *next++ = '.'; - for (int j = decimalPoint; j < 0; j++) - *next++ = '0'; - append(next, result, length); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - append(next, result, length); - for (int j = 0; j < decimalPoint - length; j++) - *next++ = '0'; - } else { - append(next, result, decimalPoint); - *next++ = '.'; - append(next, result + decimalPoint, length - decimalPoint); +unsigned numberToString(double d, NumberToStringBuffer buffer) +{ + // Handle NaN and Infinity. + if (isnan(d) || isinf(d)) { + if (isnan(d)) { + copyAsciiToUTF16(buffer, "NaN", 3); + return 3; } - } else if (result[0] < '0' || result[0] > '9') - append(next, result, length); - else { - *next++ = result[0]; - if (length > 1) { - *next++ = '.'; - append(next, result + 1, length - 1); + if (d > 0) { + copyAsciiToUTF16(buffer, "Infinity", 8); + return 8; } + copyAsciiToUTF16(buffer, "-Infinity", 9); + return 9; + } - *next++ = 'e'; - *next++ = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - *next++ = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - *next++ = static_cast<char>('0' + (exponential % 100) / 10); - *next++ = static_cast<char>('0' + exponential % 10); - } - if (resultLength) - *resultLength = next - buffer; + // Convert to decimal with rounding. + DecimalNumber number(d); + return number.exponent() >= -6 && number.exponent() < 21 + ? number.toStringDecimal(buffer, NumberToStringBufferLength) + : number.toStringExponential(buffer, NumberToStringBufferLength); } } // namespace WTF diff --git a/JavaScriptCore/wtf/dtoa.h b/JavaScriptCore/wtf/dtoa.h index 6127f53..3924a1c 100644 --- a/JavaScriptCore/wtf/dtoa.h +++ b/JavaScriptCore/wtf/dtoa.h @@ -21,27 +21,31 @@ #ifndef WTF_dtoa_h #define WTF_dtoa_h -namespace WTF { - class Mutex; -} +#include <wtf/unicode/Unicode.h> namespace WTF { +class Mutex; + +extern WTF::Mutex* s_dtoaP5Mutex; - extern WTF::Mutex* s_dtoaP5Mutex; +// s00: input string. Must not be 0 and must be terminated by 0. +// se: *se will have the last consumed character position + 1. +double strtod(const char* s00, char** se); - double strtod(const char* s00, char** se); +typedef char DtoaBuffer[80]; - typedef char DtoaBuffer[80]; - void dtoa(DtoaBuffer result, double d, int ndigits, int* decpt, int* sign, char** rve); +void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision); +void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); +void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); - // dtoa() for ECMA-262 'ToString Applied to the Number Type.' - // The *resultLength will have the length of the resultant string in bufer. - // The resultant string isn't terminated by 0. - void doubleToStringInJavaScriptFormat(double, DtoaBuffer, unsigned* resultLength); +// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits. +const unsigned NumberToStringBufferLength = 96; +typedef UChar NumberToStringBuffer[NumberToStringBufferLength]; +unsigned numberToString(double, NumberToStringBuffer); } // namespace WTF -using WTF::DtoaBuffer; -using WTF::doubleToStringInJavaScriptFormat; +using WTF::NumberToStringBuffer; +using WTF::numberToString; #endif // WTF_dtoa_h diff --git a/JavaScriptCore/wtf/efl/MainThreadEfl.cpp b/JavaScriptCore/wtf/efl/MainThreadEfl.cpp new file mode 100644 index 0000000..8774d20 --- /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 Eina_Bool 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..8dcfb9e 100644 --- a/JavaScriptCore/wtf/gtk/GOwnPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.cpp @@ -19,6 +19,9 @@ #include "config.h" #include "GOwnPtr.h" +#if ENABLE(GLIB_SUPPORT) + +#include <gio/gio.h> #include <glib.h> namespace WTF { @@ -57,4 +60,12 @@ 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 + +#endif // ENABLE(GLIB_SUPPORT) diff --git a/JavaScriptCore/wtf/gtk/GOwnPtr.h b/JavaScriptCore/wtf/gobject/GOwnPtr.h index ad2c30e..cec3e43 100644 --- a/JavaScriptCore/wtf/gtk/GOwnPtr.h +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.h @@ -22,19 +22,12 @@ #ifndef GOwnPtr_h #define GOwnPtr_h +#if ENABLE(GLIB_SUPPORT) + #include <algorithm> #include <wtf/Assertions.h> #include <wtf/Noncopyable.h> -// Forward delcarations at this point avoid the need to include GLib includes -// in WTF headers. -typedef struct _GError GError; -typedef struct _GList GList; -typedef struct _GCond GCond; -typedef struct _GMutex GMutex; -typedef struct _GPatternSpec GPatternSpec; -typedef struct _GDir GDir; -typedef struct _GHashTable GHashTable; extern "C" void g_free(void*); namespace WTF { @@ -46,7 +39,7 @@ template<> void freeOwnedGPtr<GCond>(GCond*); 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: @@ -76,8 +69,9 @@ public: void clear() { - freeOwnedGPtr(m_ptr); + T* ptr = m_ptr; m_ptr = 0; + freeOwnedGPtr(ptr); } T& operator*() const @@ -143,4 +137,7 @@ template <typename T> inline void freeOwnedGPtr(T* ptr) using WTF::GOwnPtr; +#endif // ENABLE(GLIB_SUPPORT) + #endif // GOwnPtr_h + diff --git a/JavaScriptCore/wtf/gtk/GRefPtr.cpp b/JavaScriptCore/wtf/gobject/GRefPtr.cpp index e7cf34b..085684e 100644 --- a/JavaScriptCore/wtf/gtk/GRefPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GRefPtr.cpp @@ -19,20 +19,68 @@ #include "config.h" #include "GRefPtr.h" +#if ENABLE(GLIB_SUPPORT) + #include <glib.h> namespace WTF { -template <> GHashTable* refGPtr(GHashTable* ptr) +template <> GHashTable* refPlatformPtr(GHashTable* ptr) { if (ptr) g_hash_table_ref(ptr); return ptr; } -template <> void derefGPtr(GHashTable* ptr) +template <> void derefPlatformPtr(GHashTable* ptr) { g_hash_table_unref(ptr); } +#if GLIB_CHECK_VERSION(2, 24, 0) +template <> GVariant* refPlatformPtr(GVariant* ptr) +{ + if (ptr) + g_variant_ref(ptr); + return ptr; +} + +template <> void derefPlatformPtr(GVariant* ptr) +{ + g_variant_unref(ptr); +} + +#else + +// We do this so that we can avoid including the glib.h header in GRefPtr.h. +typedef struct _GVariant { + bool fake; +} GVariant; + +template <> GVariant* refPlatformPtr(GVariant* ptr) +{ + return ptr; +} + +template <> void derefPlatformPtr(GVariant* ptr) +{ +} + +#endif + +template <> GSource* refPlatformPtr(GSource* ptr) +{ + if (ptr) + g_source_ref(ptr); + return ptr; +} + +template <> void derefPlatformPtr(GSource* ptr) +{ + if (ptr) + g_source_unref(ptr); +} + } // namespace WTF + +#endif // ENABLE(GLIB_SUPPORT) diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h new file mode 100644 index 0000000..4efd9be --- /dev/null +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2009 Martin Robinson + * + * 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 WTF_GRefPtr_h +#define WTF_GRefPtr_h + +#if ENABLE(GLIB_SUPPORT) + +#include "AlwaysInline.h" +#include "PlatformRefPtr.h" +#include <algorithm> + +extern "C" void g_object_unref(gpointer); +extern "C" gpointer g_object_ref_sink(gpointer); + +namespace WTF { + +template <> GHashTable* refPlatformPtr(GHashTable* ptr); +template <> void derefPlatformPtr(GHashTable* ptr); +template <> GVariant* refPlatformPtr(GVariant* ptr); +template <> void derefPlatformPtr(GVariant* ptr); +template <> GSource* refPlatformPtr(GSource* ptr); +template <> void derefPlatformPtr(GSource* ptr); + +template <typename T> inline T* refPlatformPtr(T* ptr) +{ + if (ptr) + g_object_ref_sink(ptr); + return ptr; +} + +template <typename T> inline void derefPlatformPtr(T* ptr) +{ + if (ptr) + g_object_unref(ptr); +} + +} // namespace WTF + +#endif // ENABLE(GLIB_SUPPORT) + +#endif // WTF_GRefPtr_h diff --git a/JavaScriptCore/wtf/gobject/GTypedefs.h b/JavaScriptCore/wtf/gobject/GTypedefs.h new file mode 100644 index 0000000..76d1b1a --- /dev/null +++ b/JavaScriptCore/wtf/gobject/GTypedefs.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 Igalia, S.L. + * + * 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 GtkTypedefs_h +#define GtkTypedefs_h + +/* Vanilla C code does not seem to be able to handle forward-declaration typedefs. */ +#ifdef __cplusplus + +typedef char gchar; +typedef double gdouble; +typedef float gfloat; +typedef int gint; +typedef gint gboolean; +typedef long glong; +typedef short gshort; +typedef unsigned char guchar; +typedef unsigned int guint; +typedef unsigned long gulong; +typedef unsigned short gushort; +typedef void* gpointer; + +typedef struct _GAsyncResult GAsyncResult; +typedef struct _GCancellable GCancellable; +typedef struct _GCharsetConverter GCharsetConverter; +typedef struct _GCond GCond; +typedef struct _GDir GDir; +typedef struct _GdkAtom* GdkAtom; +typedef struct _GdkCursor GdkCursor; +typedef struct _GdkDragContext GdkDragContext; +typedef struct _GdkDrawable GdkDrawable; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkPixbuf GdkPixbuf; +typedef struct _GError GError; +typedef struct _GFile GFile; +typedef struct _GHashTable GHashTable; +typedef struct _GInputStream GInputStream; +typedef struct _GList GList; +typedef struct _GMutex GMutex; +typedef struct _GOutputStream GOutputStream; +typedef struct _GPatternSpec GPatternSpec; +typedef struct _GSocketClient GSocketClient; +typedef struct _GSocketConnection GSocketConnection; +typedef struct _GSource GSource; +typedef struct _GVariant GVariant; +typedef union _GdkEvent GdkEvent; + +#if PLATFORM(CAIRO) +typedef struct _cairo_surface cairo_surface_t; +#endif + +#if PLATFORM(GTK) +typedef struct _GtkAction GtkAction; +typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkBorder GtkBorder; +typedef struct _GtkClipboard GtkClipboard; +typedef struct _GtkContainer GtkContainer; +typedef struct _GtkIconInfo GtkIconInfo; +typedef struct _GtkMenu GtkMenu; +typedef struct _GtkMenuItem GtkMenuItem; +typedef struct _GtkObject GtkObject; +typedef struct _GtkSelectionData GtkSelectionData; +typedef struct _GtkStyle GtkStyle; +typedef struct _GtkTargetList GtkTargetList; +typedef struct _GtkThemeParts GtkThemeParts; +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; + +#ifdef GTK_API_VERSION_2 +typedef struct _GdkRectangle GdkRectangle; +#else +typedef struct _cairo_rectangle_int cairo_rectangle_int_t; +typedef cairo_rectangle_int_t GdkRectangle; +#endif + +#endif + +#endif +#endif /* GtkTypedefs_h */ diff --git a/JavaScriptCore/wtf/gtk/GRefPtr.h b/JavaScriptCore/wtf/gtk/GRefPtr.h deleted file mode 100644 index 66739ef..0000000 --- a/JavaScriptCore/wtf/gtk/GRefPtr.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora Ltd. - * Copyright (C) 2009 Martin Robinson - * - * 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 WTF_GRefPtr_h -#define WTF_GRefPtr_h - -#include "AlwaysInline.h" -#include <algorithm> - -typedef struct _GHashTable GHashTable; - -namespace WTF { - -enum GRefPtrAdoptType { GRefPtrAdopt }; -template <typename T> inline T* refGPtr(T*); -template <typename T> inline void derefGPtr(T*); -template <typename T> class GRefPtr; -template <typename T> GRefPtr<T> adoptGRef(T*); -template <> GHashTable* refGPtr(GHashTable* ptr); -template <> void derefGPtr(GHashTable* ptr); - -template <typename T> class GRefPtr { -public: - GRefPtr() : m_ptr(0) { } - GRefPtr(T* ptr) : m_ptr(ptr) { if (ptr) refGPtr(ptr); } - GRefPtr(const GRefPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) refGPtr(ptr); } - template <typename U> GRefPtr(const GRefPtr<U>& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) refGPtr(ptr); } - - ~GRefPtr() { if (T* ptr = m_ptr) derefGPtr(ptr); } - - void clear() - { - if (T* ptr = m_ptr) - derefGPtr(ptr); - m_ptr = 0; - } - - T* get() const { return m_ptr; } - T& operator*() const { return *m_ptr; } - ALWAYS_INLINE T* operator->() const { 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* GRefPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &GRefPtr::m_ptr : 0; } - - GRefPtr& operator=(const GRefPtr&); - GRefPtr& operator=(T*); - template <typename U> GRefPtr& operator=(const GRefPtr<U>&); - - void swap(GRefPtr&); - friend GRefPtr adoptGRef<T>(T*); - -private: - static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } - // Adopting constructor. - GRefPtr(T* ptr, GRefPtrAdoptType) : m_ptr(ptr) {} - - T* m_ptr; -}; - -template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(const GRefPtr<T>& o) -{ - T* optr = o.get(); - if (optr) - refGPtr(optr); - T* ptr = m_ptr; - m_ptr = optr; - if (ptr) - derefGPtr(ptr); - return *this; -} - -template <typename T> inline GRefPtr<T>& GRefPtr<T>::operator=(T* optr) -{ - T* ptr = m_ptr; - if (optr) - refGPtr(optr); - m_ptr = optr; - if (ptr) - derefGPtr(ptr); - return *this; -} - -template <class T> inline void GRefPtr<T>::swap(GRefPtr<T>& o) -{ - std::swap(m_ptr, o.m_ptr); -} - -template <class T> inline void swap(GRefPtr<T>& a, GRefPtr<T>& b) -{ - a.swap(b); -} - -template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, const GRefPtr<U>& b) -{ - return a.get() == b.get(); -} - -template <typename T, typename U> inline bool operator==(const GRefPtr<T>& a, U* b) -{ - return a.get() == b; -} - -template <typename T, typename U> inline bool operator==(T* a, const GRefPtr<U>& b) -{ - return a == b.get(); -} - -template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, const GRefPtr<U>& b) -{ - return a.get() != b.get(); -} - -template <typename T, typename U> inline bool operator!=(const GRefPtr<T>& a, U* b) -{ - return a.get() != b; -} - -template <typename T, typename U> inline bool operator!=(T* a, const GRefPtr<U>& b) -{ - return a != b.get(); -} - -template <typename T, typename U> inline GRefPtr<T> static_pointer_cast(const GRefPtr<U>& p) -{ - return GRefPtr<T>(static_cast<T*>(p.get())); -} - -template <typename T, typename U> inline GRefPtr<T> const_pointer_cast(const GRefPtr<U>& p) -{ - return GRefPtr<T>(const_cast<T*>(p.get())); -} - -template <typename T> inline T* getPtr(const GRefPtr<T>& p) -{ - return p.get(); -} - -template <typename T> GRefPtr<T> adoptGRef(T* p) -{ - return GRefPtr<T>(p, GRefPtrAdopt); -} - -template <typename T> inline T* refGPtr(T* ptr) -{ - if (ptr) - g_object_ref_sink(ptr); - return ptr; -} - -template <typename T> inline void derefGPtr(T* ptr) -{ - if (ptr) - g_object_unref(ptr); -} - -} // namespace WTF - -using WTF::GRefPtr; -using WTF::refGPtr; -using WTF::derefGPtr; -using WTF::adoptGRef; -using WTF::static_pointer_cast; -using WTF::const_pointer_cast; - -#endif // WTF_GRefPtr_h diff --git a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp index a6ec8f7..863ee81 100644 --- a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp +++ b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp @@ -36,19 +36,20 @@ #include "HashMap.h" #include "MainThread.h" #include "RandomNumberSeed.h" +#include <wtf/StdLibExtras.h> #include <glib.h> #include <limits.h> namespace WTF { -static Mutex* atomicallyInitializedStaticMutex; +typedef HashMap<ThreadIdentifier, GThread*> ThreadMap; -static ThreadIdentifier mainThreadIdentifier; +static Mutex* atomicallyInitializedStaticMutex; static Mutex& threadMapMutex() { - static Mutex mutex; + DEFINE_STATIC_LOCAL(Mutex, mutex, ()); return mutex; } @@ -62,8 +63,6 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); - mainThreadIdentifier = currentThread(); - initializeMainThread(); } } @@ -78,9 +77,9 @@ void unlockAtomicallyInitializedStaticMutex() atomicallyInitializedStaticMutex->unlock(); } -static HashMap<ThreadIdentifier, GThread*>& threadMap() +static ThreadMap& threadMap() { - static HashMap<ThreadIdentifier, GThread*> map; + DEFINE_STATIC_LOCAL(ThreadMap, map, ()); return map; } @@ -88,7 +87,7 @@ static ThreadIdentifier identifierByGthreadHandle(GThread*& thread) { MutexLocker locker(threadMapMutex()); - HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin(); + ThreadMap::iterator i = threadMap().begin(); for (; i != threadMap().end(); ++i) { if (i->second == thread) return i->first; @@ -168,9 +167,9 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() +void yield() { - return currentThread() == mainThreadIdentifier; + g_thread_yield(); } Mutex::Mutex() 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..16dd439 --- /dev/null +++ b/JavaScriptCore/wtf/qt/StringQt.cpp @@ -0,0 +1,73 @@ +/* + * 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/StdLibExtras.h> +#include <wtf/text/WTFString.h> + +#include <QString> + +namespace WTF { + +// String conversions +String::String(const QString& qstr) +{ + if (qstr.isNull()) + return; + m_impl = StringImpl::create(reinterpret_cast_ptr<const UChar*>(qstr.constData()), qstr.length()); +} + +String::String(const QStringRef& ref) +{ + if (!ref.string()) + return; + m_impl = StringImpl::create(reinterpret_cast_ptr<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..8041dea 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,9 +208,9 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() +void yield() { - return QThread::currentThread() == QCoreApplication::instance()->thread(); + QThread::yieldCurrentThread(); } Mutex::Mutex() diff --git a/JavaScriptCore/wtf/text/AtomicString.cpp b/JavaScriptCore/wtf/text/AtomicString.cpp new file mode 100644 index 0000000..c49a837 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicString.cpp @@ -0,0 +1,306 @@ +/* + * 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" + +#include "AtomicString.h" + +#include "StringHash.h" +#include <wtf/HashSet.h> +#include <wtf/Threading.h> +#include <wtf/WTFThreadData.h> + +namespace WTF { + +COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size); + +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).leakRef(); + 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) || CPU(MIPS) + 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 +} + +bool operator==(const AtomicString& string, const Vector<UChar>& vector) +{ + return string.impl() && equal(string.impl(), vector.data(), vector.size()); +} + +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 WTF::equal(str, buf.s, buf.length); + } + + static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash) + { + location = StringImpl::create(buf.s, buf.length).leakRef(); + 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 WTF::equal(string, buffer.characters, buffer.length); + } + + static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash) + { + location = StringImpl::create(buffer.characters, buffer.length).leakRef(); + 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::addSlowCase(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(); + if (UNLIKELY(!impl)) + return *this; + RefPtr<StringImpl> newImpl = impl->lower(); + if (LIKELY(newImpl == impl)) + return *this; + return AtomicString(newImpl); +} + +} diff --git a/JavaScriptCore/wtf/text/AtomicString.h b/JavaScriptCore/wtf/text/AtomicString.h new file mode 100644 index 0000000..06e63f4 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicString.h @@ -0,0 +1,180 @@ +/* + * 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 + +namespace WTF { + +struct AtomicStringHash; + +class AtomicString { +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); } + + size_t find(UChar c, size_t start = 0) const { return m_string.find(c, start); } + size_t find(const char* s, size_t start = 0, bool caseSentitive = true) const + { return m_string.find(s, start, caseSentitive); } + size_t find(const String& s, size_t 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*); + ALWAYS_INLINE PassRefPtr<StringImpl> add(StringImpl* r) + { + if (!r || r->isAtomic()) + return r; + return addSlowCase(r); + } + static PassRefPtr<StringImpl> addSlowCase(StringImpl*); +}; + +inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } +bool operator==(const AtomicString& a, const char* b); +bool operator==(const AtomicString& a, const Vector<UChar>& 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 Vector<UChar>& a, const AtomicString& b) { return b == a; } + +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 AtomicString& a, const Vector<UChar>& b) { return !(a == b); } +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 Vector<UChar>& a, const AtomicString& b) { return !(a == b); } + +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 + + // AtomicStringHash is the default hash for AtomicString + template<typename T> struct DefaultHash; + template<> struct DefaultHash<AtomicString> { + typedef AtomicStringHash Hash; + }; + +} // namespace WTF + +#ifndef ATOMICSTRING_HIDE_GLOBALS +using WTF::AtomicString; +using WTF::nullAtom; +using WTF::emptyAtom; +using WTF::textAtom; +using WTF::commentAtom; +using WTF::starAtom; +using WTF::xmlAtom; +using WTF::xmlnsAtom; +#endif + +#endif // AtomicString_h diff --git a/JavaScriptCore/wtf/text/AtomicStringHash.h b/JavaScriptCore/wtf/text/AtomicStringHash.h new file mode 100644 index 0000000..f6e4ad1 --- /dev/null +++ b/JavaScriptCore/wtf/text/AtomicStringHash.h @@ -0,0 +1,62 @@ +/* + * 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 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 AtomicStringHash_h +#define AtomicStringHash_h + +#include <wtf/text/AtomicString.h> +#include <wtf/HashTraits.h> + +namespace WTF { + + struct AtomicStringHash { + static unsigned hash(const AtomicString& key) + { + return key.impl()->existingHash(); + } + + static bool equal(const AtomicString& a, const AtomicString& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = false; + }; + + // AtomicStringHash is the default hash for AtomicString + template<> struct HashTraits<WTF::AtomicString> : GenericHashTraits<WTF::AtomicString> { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(WTF::AtomicString& slot) { new (&slot) WTF::AtomicString(HashTableDeletedValue); } + static bool isDeletedValue(const WTF::AtomicString& slot) { return slot.isHashTableDeletedValue(); } + }; + +} + +using WTF::AtomicStringHash; + +#endif diff --git a/JavaScriptCore/wtf/text/AtomicStringImpl.h b/JavaScriptCore/wtf/text/AtomicStringImpl.h new file mode 100644 index 0000000..3f0c376 --- /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" + +namespace WTF { + +class AtomicStringImpl : public StringImpl +{ +public: + AtomicStringImpl() : StringImpl(0) {} +}; + +} + +using WTF::AtomicStringImpl; + +#endif diff --git a/JavaScriptCore/wtf/text/CString.cpp b/JavaScriptCore/wtf/text/CString.cpp new file mode 100644 index 0000000..db6443f --- /dev/null +++ b/JavaScriptCore/wtf/text/CString.cpp @@ -0,0 +1,101 @@ +/* + * 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. + */ + + +#include "config.h" +#include "CString.h" + +using namespace std; + +namespace WTF { + +CString::CString(const char* str) +{ + if (!str) + return; + + init(str, strlen(str)); +} + +CString::CString(const char* str, size_t length) +{ + init(str, length); +} + +void CString::init(const char* str, size_t length) +{ + if (!str) + return; + + if (length >= numeric_limits<size_t>::max()) + CRASH(); + + m_buffer = CStringBuffer::create(length + 1); + memcpy(m_buffer->mutableData(), str, length); + m_buffer->mutableData()[length] = '\0'; +} + +char* CString::mutableData() +{ + copyBufferIfNeeded(); + if (!m_buffer) + return 0; + return m_buffer->mutableData(); +} + +CString CString::newUninitialized(size_t length, char*& characterBuffer) +{ + if (length >= numeric_limits<size_t>::max()) + CRASH(); + + 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; + + RefPtr<CStringBuffer> buffer = m_buffer.release(); + size_t length = buffer->length(); + m_buffer = CStringBuffer::create(length); + memcpy(m_buffer->mutableData(), buffer->data(), length); +} + +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..343a7a5 --- /dev/null +++ b/JavaScriptCore/wtf/text/CString.h @@ -0,0 +1,87 @@ +/* + * 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(size_t length) { return adoptRef(new CStringBuffer(length)); } + CStringBuffer(size_t 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*, size_t length); + CString(CStringBuffer* buffer) : m_buffer(buffer) { } + static CString newUninitialized(size_t length, char*& characterBuffer); + + const char* data() const + { + return m_buffer ? m_buffer->data() : 0; + } + char* mutableData(); + size_t length() const + { + return m_buffer ? m_buffer->length() - 1 : 0; + } + + bool isNull() const { return !m_buffer; } + + CStringBuffer* buffer() const { return m_buffer.get(); } + +private: + void copyBufferIfNeeded(); + void init(const char*, size_t 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..a546bf3 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringBuffer.h @@ -0,0 +1,86 @@ +/* + * 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. + * 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> +#include <limits> + +namespace WTF { + +class StringBuffer : public Noncopyable { +public: + explicit StringBuffer(unsigned length) + : m_length(length) + { + if (m_length > std::numeric_limits<unsigned>::max() / sizeof(UChar)) + CRASH(); + m_data = static_cast<UChar*>(fastMalloc(m_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) { + if (newLength > std::numeric_limits<unsigned>::max() / sizeof(UChar)) + CRASH(); + 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; +}; + +} // namespace WTF + +using WTF::StringBuffer; + +#endif // StringBuffer_h diff --git a/JavaScriptCore/wtf/text/StringBuilder.cpp b/JavaScriptCore/wtf/text/StringBuilder.cpp new file mode 100644 index 0000000..dfc9ff3 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringBuilder.cpp @@ -0,0 +1,172 @@ +/* + * 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. + */ + +#include "config.h" +#include "StringBuilder.h" + +#include "WTFString.h" + +namespace WTF { + +void StringBuilder::reifyString() +{ + // Check if the string already exists. + if (!m_string.isNull()) { + ASSERT(m_string.length() == m_length); + return; + } + + // Check for empty. + if (!m_length) { + m_string = StringImpl::empty(); + return; + } + + // Must be valid in the buffer, take a substring (unless string fills the buffer). + ASSERT(m_buffer && m_length <= m_buffer->length()); + m_string = (m_length == m_buffer->length()) + ? m_buffer.get() + : StringImpl::create(m_buffer, 0, m_length); +} + +void StringBuilder::resize(unsigned newSize) +{ + // Check newSize < m_length, hence m_length > 0. + ASSERT(newSize <= m_length); + if (newSize == m_length) + return; + ASSERT(m_length); + + // If there is a buffer, we only need to duplicate it if it has more than one ref. + if (m_buffer) { + if (!m_buffer->hasOneRef()) + allocateBuffer(m_buffer->characters(), m_buffer->length()); + m_length = newSize; + m_string = String(); + return; + } + + // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0. + ASSERT(!m_string.isEmpty()); + ASSERT(m_length == m_string.length()); + ASSERT(newSize < m_string.length()); + m_length = newSize; + m_string = StringImpl::create(m_string.impl(), 0, newSize); +} + +void StringBuilder::reserveCapacity(unsigned newCapacity) +{ + if (m_buffer) { + // If there is already a buffer, then grow if necessary. + if (newCapacity > m_buffer->length()) + allocateBuffer(m_buffer->characters(), newCapacity); + } else { + // Grow the string, if necessary. + if (newCapacity > m_length) + allocateBuffer(m_string.characters(), newCapacity); + } +} + +// Allocate a new buffer, copying in currentCharacters (these may come from either m_string +// or m_buffer, neither will be reassigned until the copy has completed). +void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength) +{ + // Copy the existing data into a new buffer, set result to point to the end of the existing data. + RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters); + memcpy(m_bufferCharacters, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow. + + // Update the builder state. + m_buffer = buffer.release(); + m_string = String(); +} + +// Make 'length' additional capacity be available in m_buffer, update m_string & m_length, +// return a pointer to the newly allocated storage. +UChar* StringBuilder::appendUninitialized(unsigned length) +{ + ASSERT(length); + + // Calcuate the new size of the builder after appending. + unsigned requiredLength = length + m_length; + if (requiredLength < length) + CRASH(); + + if (m_buffer) { + // If the buffer is valid it must be at least as long as the current builder contents! + ASSERT(m_buffer->length() >= m_length); + + // Check if the buffer already has sufficient capacity. + if (requiredLength <= m_buffer->length()) { + unsigned currentLength = m_length; + m_string = String(); + m_length = requiredLength; + return m_bufferCharacters + currentLength; + } + + // We need to realloc the buffer. + allocateBuffer(m_buffer->characters(), std::max(requiredLength, m_buffer->length() * 2)); + } else { + ASSERT(m_string.length() == m_length); + allocateBuffer(m_string.characters(), std::max(requiredLength, requiredLength * 2)); + } + + UChar* result = m_bufferCharacters + m_length; + m_length = requiredLength; + return result; +} + +void StringBuilder::append(const UChar* characters, unsigned length) +{ + if (!length) + return; + ASSERT(characters); + + memcpy(appendUninitialized(length), characters, static_cast<size_t>(length) * 2); +} + +void StringBuilder::append(const char* characters, unsigned length) +{ + if (!length) + return; + ASSERT(characters); + + UChar* dest = appendUninitialized(length); + const char* end = characters + length; + while (characters < end) + *(dest++) = *(const unsigned char*)(characters++); +} + +void StringBuilder::shrinkToFit() +{ + // If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic! + if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) { + UChar* result; + m_string = StringImpl::createUninitialized(m_length, result); + memcpy(result, m_buffer->characters(), static_cast<size_t>(m_length) * 2); // This can't overflow. + m_buffer = 0; + } +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/text/StringBuilder.h b/JavaScriptCore/wtf/text/StringBuilder.h new file mode 100644 index 0000000..f10af64 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringBuilder.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 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 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 StringBuilder_h +#define StringBuilder_h + +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace WTF { + +class StringBuilder { +public: + StringBuilder() + : m_length(0) + { + } + + void append(const UChar*, unsigned); + void append(const char*, unsigned); + + void append(const String& string) + { + // If we're appending to an empty string, and there is not buffer + // (in case reserveCapacity has been called) then just retain the + // string. + if (!m_length && !m_buffer) { + m_string = string; + m_length = string.length(); + return; + } + append(string.characters(), string.length()); + } + + void append(const char* characters) + { + if (characters) + append(characters, strlen(characters)); + } + + void append(UChar c) + { + if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) + m_bufferCharacters[m_length++] = c; + else + append(&c, 1); + } + + void append(char c) + { + if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) + m_bufferCharacters[m_length++] = (unsigned char)c; + else + append(&c, 1); + } + + String toString() + { + if (m_string.isNull()) { + shrinkToFit(); + reifyString(); + } + return m_string; + } + + String toStringPreserveCapacity() + { + if (m_string.isNull()) + reifyString(); + return m_string; + } + + unsigned length() const + { + return m_length; + } + + bool isEmpty() const { return !length(); } + + void reserveCapacity(unsigned newCapacity); + + void resize(unsigned newSize); + + void shrinkToFit(); + + UChar operator[](unsigned i) const + { + ASSERT(i < m_length); + if (!m_string.isNull()) + return m_string[i]; + ASSERT(m_buffer); + return m_buffer->characters()[i]; + } + + void clear() + { + m_length = 0; + m_string = String(); + m_buffer = 0; + } + +private: + void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength); + UChar* appendUninitialized(unsigned length); + void reifyString(); + + unsigned m_length; + String m_string; + RefPtr<StringImpl> m_buffer; + UChar* m_bufferCharacters; +}; + +} // namespace WTF + +using WTF::StringBuilder; + +#endif // StringBuilder_h diff --git a/JavaScriptCore/wtf/text/StringConcatenate.h b/JavaScriptCore/wtf/text/StringConcatenate.h new file mode 100644 index 0000000..b54a108 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringConcatenate.h @@ -0,0 +1,467 @@ +/* + * 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 StringConcatenate_h +#define StringConcatenate_h + +#include <wtf/text/WTFString.h> + +namespace WTF { + +template<typename StringType> +class StringTypeAdapter { +}; + +template<> +class StringTypeAdapter<char> { +public: + StringTypeAdapter<char>(char buffer) + : m_buffer(buffer) + { + } + + unsigned length() { return 1; } + void writeTo(UChar* destination) { *destination = m_buffer; } + +private: + unsigned char m_buffer; +}; + +template<> +class StringTypeAdapter<UChar> { +public: + StringTypeAdapter<UChar>(UChar buffer) + : m_buffer(buffer) + { + } + + unsigned length() { return 1; } + void writeTo(UChar* destination) { *destination = m_buffer; } + +private: + UChar m_buffer; +}; + +template<> +class StringTypeAdapter<char*> { +public: + StringTypeAdapter<char*>(char* buffer) + : m_buffer((unsigned char*)buffer) + , m_length(strlen(buffer)) + { + } + + unsigned length() { return m_length; } + + void writeTo(UChar* destination) + { + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_buffer[i]; + } + +private: + const unsigned char* m_buffer; + unsigned m_length; +}; + +template<> +class StringTypeAdapter<const char*> { +public: + StringTypeAdapter<const char*>(const char* buffer) + : m_buffer((unsigned char*)buffer) + , m_length(strlen(buffer)) + { + } + + unsigned length() { return m_length; } + + void writeTo(UChar* destination) + { + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_buffer[i]; + } + +private: + const unsigned char* m_buffer; + unsigned m_length; +}; + +template<> +class StringTypeAdapter<String> { +public: + StringTypeAdapter<String>(String& string) + : m_data(string.characters()) + , m_length(string.length()) + { + } + + unsigned length() { return m_length; } + + void writeTo(UChar* destination) + { + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_data[i]; + } + +private: + const UChar* m_data; + unsigned m_length; +}; + +inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow) +{ + unsigned oldTotal = total; + total = oldTotal + addend; + if (total < oldTotal) + overflow = true; +} + +template<typename StringType1, typename StringType2> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + + UChar* buffer = 0; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + StringTypeAdapter<StringType7> adapter7(string7); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + sumWithOverflow(length, adapter7.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + result += adapter6.length(); + adapter7.writeTo(result); + + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8> +PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) +{ + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + StringTypeAdapter<StringType7> adapter7(string7); + StringTypeAdapter<StringType8> adapter8(string8); + + UChar* buffer; + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + sumWithOverflow(length, adapter7.length(), overflow); + sumWithOverflow(length, adapter8.length(), overflow); + if (overflow) + return 0; + PassRefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return 0; + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + result += adapter6.length(); + adapter7.writeTo(result); + result += adapter7.length(); + adapter8.writeTo(result); + + return resultImpl; +} + +// Convenience only. +template<typename StringType1> +String makeString(StringType1 string1) +{ + return String(string1); +} + +template<typename StringType1, typename StringType2> +String makeString(StringType1 string1, StringType2 string2) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8> +String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) +{ + PassRefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8); + if (!resultImpl) + CRASH(); + return resultImpl; +} + +} // namespace WTF + +using WTF::makeString; + +#endif diff --git a/JavaScriptCore/wtf/text/StringHash.h b/JavaScriptCore/wtf/text/StringHash.h new file mode 100644 index 0000000..d7aabdb --- /dev/null +++ b/JavaScriptCore/wtf/text/StringHash.h @@ -0,0 +1,194 @@ +/* + * 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/Forward.h> +#include <wtf/HashTraits.h> +#include <wtf/StringHasher.h> +#include <wtf/unicode/Unicode.h> + +namespace WTF { + + // 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) || CPU(MIPS) + 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: + template<typename T> static inline UChar foldCase(T ch) + { + return WTF::Unicode::foldCase(ch); + } + + static unsigned hash(const UChar* data, unsigned length) + { + return StringHasher::createHash<UChar, foldCase<UChar> >(data, length); + } + + static unsigned hash(StringImpl* str) + { + return hash(str->characters(), str->length()); + } + + static unsigned hash(const char* data, unsigned length) + { + return StringHasher::createHash<char, foldCase<char> >(data, length); + } + + 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; + } + }; + + template<> struct HashTraits<String> : GenericHashTraits<String> { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(String& slot) { new (&slot) String(HashTableDeletedValue); } + static bool isDeletedValue(const String& slot) { return slot.isHashTableDeletedValue(); } + }; + +} + +using WTF::StringHash; +using WTF::CaseFoldingHash; +using WTF::AlreadyHashed; + +#endif diff --git a/JavaScriptCore/wtf/text/StringImpl.cpp b/JavaScriptCore/wtf/text/StringImpl.cpp new file mode 100644 index 0000000..c83ec42 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringImpl.cpp @@ -0,0 +1,1073 @@ +/* + * 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 std; + +namespace WTF { + +using namespace Unicode; + +static const unsigned minLengthToShare = 20; + +COMPILE_ASSERT(sizeof(StringImpl) == 2 * sizeof(int) + 3 * sizeof(void*), StringImpl_should_stay_small); + +StringImpl::~StringImpl() +{ + ASSERT(!isStatic()); + + if (isAtomic()) + AtomicString::remove(this); +#if USE(JSC) + if (isIdentifier()) { + if (!wtfThreadData().currentIdentifierTable()->remove(this)) + CRASH(); + } +#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(); + } + } +} + +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<unsigned>::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; + RefPtr<StringImpl> string = createUninitialized(length, data); + memcpy(data, characters, length * sizeof(UChar)); + return string.release(); +} + +PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length) +{ + if (!characters || !length) + return empty(); + + UChar* data; + RefPtr<StringImpl> string = createUninitialized(length, data); + for (unsigned i = 0; i != length; ++i) { + unsigned char c = characters[i]; + data[i] = c; + } + return string.release(); +} + +PassRefPtr<StringImpl> StringImpl::create(const char* string) +{ + if (!string) + return empty(); + size_t length = strlen(string); + if (length > numeric_limits<unsigned>::max()) + CRASH(); + return create(string, length); +} + +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)).leakRef(); + 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; + + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); + 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; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); + 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.release(); + + // 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.release(); +} + +PassRefPtr<StringImpl> StringImpl::secure(UChar character, LastCharacterBehavior behavior) +{ + if (!m_length) + return this; + + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + unsigned lastCharacterIndex = m_length - 1; + for (unsigned i = 0; i < lastCharacterIndex; ++i) + data[i] = character; + data[lastCharacterIndex] = (behavior == ObscureLastCharacter) ? character : m_data[lastCharacterIndex]; + return newImpl.release(); +} + +PassRefPtr<StringImpl> StringImpl::foldCase() +{ + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(m_length, data); + + if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max())) + CRASH(); + int32_t length = m_length; + + // Do a faster loop for the case where all the characters are ASCII. + UChar ored = 0; + for (int32_t i = 0; i < length; i++) { + UChar c = m_data[i]; + ored |= c; + data[i] = toASCIILower(c); + } + if (!(ored & ~0x7F)) + return newImpl.release(); + + // 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.release(); + newImpl = createUninitialized(realLength, data); + Unicode::foldCase(data, realLength, m_data, m_length, &error); + if (error) + return this; + return newImpl.release(); +} + +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 codePointCompare(const StringImpl* s1, const StringImpl* s2) +{ + const unsigned l1 = s1 ? s1->length() : 0; + const unsigned l2 = s2 ? s2->length() : 0; + const unsigned lmin = l1 < l2 ? l1 : l2; + const UChar* c1 = s1 ? s1->characters() : 0; + const UChar* c2 = s2 ? s2->characters() : 0; + unsigned pos = 0; + while (pos < lmin && *c1 == *c2) { + c1++; + c2++; + pos++; + } + + if (pos < lmin) + return (c1[0] > c2[0]) ? 1 : -1; + + if (l1 == l2) + return 0; + + return (l1 > l2) ? 1 : -1; +} + +size_t StringImpl::find(UChar c, unsigned start) +{ + return WTF::find(m_data, m_length, c, start); +} + +size_t StringImpl::find(CharacterMatchFunctionPtr matchFunction, unsigned start) +{ + return WTF::find(m_data, m_length, matchFunction, start); +} + +size_t StringImpl::find(const char* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + size_t matchStringLength = strlen(matchString); + if (matchStringLength > numeric_limits<unsigned>::max()) + CRASH(); + unsigned matchLength = matchStringLength; + if (!matchLength) + return min(index, length()); + + // Optimization 1: fast case for strings of length 1. + if (matchLength == 1) + return WTF::find(characters(), length(), *(const unsigned char*)matchString, index); + + // Check index & matchLength are in range. + if (index > length()) + return notFound; + unsigned searchLength = length() - index; + if (matchLength > searchLength) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = searchLength - matchLength; + + const UChar* searchCharacters = characters() + index; + const unsigned char* matchCharacters = (const unsigned char*)matchString; + + // Optimization 2: keep a running hash of the strings, + // only call memcmp if the hashes match. + unsigned searchHash = 0; + unsigned matchHash = 0; + for (unsigned i = 0; i < matchLength; ++i) { + searchHash += searchCharacters[i]; + matchHash += matchCharacters[i]; + } + + unsigned i = 0; + // keep looping until we match + while (searchHash != matchHash || !equal(searchCharacters + i, matchString, matchLength)) { + if (i == delta) + return notFound; + searchHash += searchCharacters[i + matchLength]; + searchHash -= searchCharacters[i]; + ++i; + } + return index + i; +} + +size_t StringImpl::findIgnoringCase(const char* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + size_t matchStringLength = strlen(matchString); + if (matchStringLength > numeric_limits<unsigned>::max()) + CRASH(); + unsigned matchLength = matchStringLength; + if (!matchLength) + return min(index, length()); + + // Check index & matchLength are in range. + if (index > length()) + return notFound; + unsigned searchLength = length() - index; + if (matchLength > searchLength) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = searchLength - matchLength; + + const UChar* searchCharacters = characters() + index; + + unsigned i = 0; + // keep looping until we match + while (!equalIgnoringCase(searchCharacters + i, matchString, matchLength)) { + if (i == delta) + return notFound; + ++i; + } + return index + i; +} + +size_t StringImpl::find(StringImpl* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + unsigned matchLength = matchString->length(); + if (!matchLength) + return min(index, length()); + + // Optimization 1: fast case for strings of length 1. + if (matchLength == 1) + return WTF::find(characters(), length(), matchString->characters()[0], index); + + // Check index & matchLength are in range. + if (index > length()) + return notFound; + unsigned searchLength = length() - index; + if (matchLength > searchLength) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = searchLength - matchLength; + + const UChar* searchCharacters = characters() + index; + const UChar* matchCharacters = matchString->characters(); + + // Optimization 2: keep a running hash of the strings, + // only call memcmp if the hashes match. + unsigned searchHash = 0; + unsigned matchHash = 0; + for (unsigned i = 0; i < matchLength; ++i) { + searchHash += searchCharacters[i]; + matchHash += matchCharacters[i]; + } + + unsigned i = 0; + // keep looping until we match + while (searchHash != matchHash || memcmp(searchCharacters + i, matchCharacters, matchLength * sizeof(UChar))) { + if (i == delta) + return notFound; + searchHash += searchCharacters[i + matchLength]; + searchHash -= searchCharacters[i]; + ++i; + } + return index + i; +} + +size_t StringImpl::findIgnoringCase(StringImpl* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + unsigned matchLength = matchString->length(); + if (!matchLength) + return min(index, length()); + + // Check index & matchLength are in range. + if (index > length()) + return notFound; + unsigned searchLength = length() - index; + if (matchLength > searchLength) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = searchLength - matchLength; + + const UChar* searchCharacters = characters() + index; + const UChar* matchCharacters = matchString->characters(); + + unsigned i = 0; + // keep looping until we match + while (!equalIgnoringCase(searchCharacters + i, matchCharacters, matchLength)) { + if (i == delta) + return notFound; + ++i; + } + return index + i; +} + +size_t StringImpl::reverseFind(UChar c, unsigned index) +{ + return WTF::reverseFind(m_data, m_length, c, index); +} + +size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + unsigned matchLength = matchString->length(); + if (!matchLength) + return min(index, length()); + + // Optimization 1: fast case for strings of length 1. + if (matchLength == 1) + return WTF::reverseFind(characters(), length(), matchString->characters()[0], index); + + // Check index & matchLength are in range. + if (matchLength > length()) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = min(index, length() - matchLength); + + const UChar *searchCharacters = characters(); + const UChar *matchCharacters = matchString->characters(); + + // Optimization 2: keep a running hash of the strings, + // only call memcmp if the hashes match. + unsigned searchHash = 0; + unsigned matchHash = 0; + for (unsigned i = 0; i < matchLength; ++i) { + searchHash += searchCharacters[delta + i]; + matchHash += matchCharacters[i]; + } + + // keep looping until we match + while (searchHash != matchHash || memcmp(searchCharacters + delta, matchCharacters, matchLength * sizeof(UChar))) { + if (!delta) + return notFound; + delta--; + searchHash -= searchCharacters[delta + matchLength]; + searchHash += searchCharacters[delta]; + } + return delta; +} + +size_t StringImpl::reverseFindIgnoringCase(StringImpl* matchString, unsigned index) +{ + // Check for null or empty string to match against + if (!matchString) + return notFound; + unsigned matchLength = matchString->length(); + if (!matchLength) + return min(index, length()); + + // Check index & matchLength are in range. + if (matchLength > length()) + return notFound; + // delta is the number of additional times to test; delta == 0 means test only once. + unsigned delta = min(index, length() - matchLength); + + const UChar *searchCharacters = characters(); + const UChar *matchCharacters = matchString->characters(); + + // keep looping until we match + while (!equalIgnoringCase(searchCharacters + delta, matchCharacters, matchLength)) { + if (!delta) + return notFound; + delta--; + } + return delta; +} + +bool StringImpl::endsWith(StringImpl* m_data, bool caseSensitive) +{ + ASSERT(m_data); + if (m_length >= m_data->m_length) { + unsigned start = m_length - m_data->m_length; + return (caseSensitive ? find(m_data, start) : findIgnoringCase(m_data, start)) == 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; + RefPtr<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.release(); +} + +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; + + if ((length() - lengthToReplace) >= (numeric_limits<unsigned>::max() - lengthToInsert)) + CRASH(); + + RefPtr<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.release(); +} + +PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacement) +{ + if (!replacement) + return this; + + unsigned repStrLength = replacement->length(); + size_t srcSegmentStart = 0; + unsigned matchCount = 0; + + // Count the matches + while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) { + ++matchCount; + ++srcSegmentStart; + } + + // If we have 0 matches, we don't have to do any more work + if (!matchCount) + return this; + + if (repStrLength && matchCount > numeric_limits<unsigned>::max() / repStrLength) + CRASH(); + + unsigned replaceSize = matchCount * repStrLength; + unsigned newSize = m_length - matchCount; + if (newSize >= (numeric_limits<unsigned>::max() - replaceSize)) + CRASH(); + + newSize += replaceSize; + + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(newSize, data); + + // Construct the new data + size_t srcSegmentEnd; + unsigned srcSegmentLength; + srcSegmentStart = 0; + unsigned dstOffset = 0; + + while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { + 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 == newImpl->length()); + + return newImpl.release(); +} + +PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement) +{ + if (!pattern || !replacement) + return this; + + unsigned patternLength = pattern->length(); + if (!patternLength) + return this; + + unsigned repStrLength = replacement->length(); + size_t srcSegmentStart = 0; + unsigned matchCount = 0; + + // Count the matches + while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) { + ++matchCount; + srcSegmentStart += patternLength; + } + + // If we have 0 matches, we don't have to do any more work + if (!matchCount) + return this; + + unsigned newSize = m_length - matchCount * patternLength; + if (repStrLength && matchCount > numeric_limits<unsigned>::max() / repStrLength) + CRASH(); + + if (newSize > (numeric_limits<unsigned>::max() - matchCount * repStrLength)) + CRASH(); + + newSize += matchCount * repStrLength; + + UChar* data; + RefPtr<StringImpl> newImpl = createUninitialized(newSize, data); + + // Construct the new data + size_t srcSegmentEnd; + unsigned srcSegmentLength; + srcSegmentStart = 0; + unsigned dstOffset = 0; + + while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) { + 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 == newImpl->length()); + + return newImpl.release(); +} + +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; +} + +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 memory block. + UChar* data; + unsigned length = string.m_length; + if (length >= numeric_limits<unsigned>::max()) + CRASH(); + 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 WTF diff --git a/JavaScriptCore/wtf/text/StringImpl.h b/JavaScriptCore/wtf/text/StringImpl.h new file mode 100644 index 0000000..99d0e9d --- /dev/null +++ b/JavaScriptCore/wtf/text/StringImpl.h @@ -0,0 +1,406 @@ +/* + * 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/Forward.h> +#include <wtf/OwnFastMallocPtr.h> +#include <wtf/StdLibExtras.h> +#include <wtf/StringHasher.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; +} + +namespace WTF { + +struct CStringTranslator; +struct HashAndCharactersTranslator; +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 WTF::CStringTranslator; + friend struct WTF::HashAndCharactersTranslator; + friend struct WTF::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.leakRef()) + , 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.leakRef()) + , 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 ALWAYS_INLINE 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 ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, UChar*& output) + { + if (!length) { + output = 0; + return empty(); + } + + if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(UChar))) { + output = 0; + return 0; + } + StringImpl* resultImpl; + if (!tryFastMalloc(sizeof(UChar) * length + sizeof(StringImpl)).getValue(resultImpl)) { + output = 0; + 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()); + if (size > std::numeric_limits<unsigned>::max()) + CRASH(); + 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::StringHasher::createHash<UChar>(data, length); } + static unsigned computeHash(const char* data, unsigned length) { return WTF::StringHasher::createHash<char>(data, length); } + static unsigned computeHash(const char* data) { return WTF::StringHasher::createHash<char>(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(); + + enum LastCharacterBehavior { ObscureLastCharacter, DisplayLastCharacter }; + + PassRefPtr<StringImpl> secure(UChar, LastCharacterBehavior = ObscureLastCharacter); + PassRefPtr<StringImpl> foldCase(); + + PassRefPtr<StringImpl> stripWhiteSpace(); + PassRefPtr<StringImpl> simplifyWhiteSpace(); + + PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr); + + size_t find(UChar, unsigned index = 0); + size_t find(CharacterMatchFunctionPtr, unsigned index = 0); + size_t find(const char*, unsigned index = 0); + size_t find(StringImpl*, unsigned index = 0); + size_t findIgnoringCase(const char*, unsigned index = 0); + size_t findIgnoringCase(StringImpl*, unsigned index = 0); + + size_t reverseFind(UChar, unsigned index = UINT_MAX); + size_t reverseFind(StringImpl*, unsigned index = UINT_MAX); + size_t reverseFindIgnoringCase(StringImpl*, unsigned index = UINT_MAX); + + bool startsWith(StringImpl* str, bool caseSensitive = true) { return (caseSensitive ? reverseFind(str, 0) : reverseFindIgnoringCase(str, 0)) == 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*); + + 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*); + +int codePointCompare(const StringImpl*, const 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); +} + +struct StringHash; + +// StringHash is the default hash for StringImpl* and RefPtr<StringImpl> +template<typename T> struct DefaultHash; +template<> struct DefaultHash<StringImpl*> { + typedef StringHash Hash; +}; +template<> struct DefaultHash<RefPtr<StringImpl> > { + typedef StringHash Hash; +}; + +} + +using WTF::StringImpl; +using WTF::equal; +using WTF::TextCaseSensitivity; +using WTF::TextCaseSensitive; +using WTF::TextCaseInsensitive; + +#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/StringStatics.cpp b/JavaScriptCore/wtf/text/StringStatics.cpp new file mode 100644 index 0000000..5654044 --- /dev/null +++ b/JavaScriptCore/wtf/text/StringStatics.cpp @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include "config.h" + +#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC +#define ATOMICSTRING_HIDE_GLOBALS 1 +#endif + +#include "AtomicString.h" +#include "StaticConstructors.h" +#include "StringImpl.h" + +namespace WTF { + +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; +} + +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/TextPosition.h b/JavaScriptCore/wtf/text/TextPosition.h new file mode 100644 index 0000000..63dc594 --- /dev/null +++ b/JavaScriptCore/wtf/text/TextPosition.h @@ -0,0 +1,141 @@ +/* + * 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: + * 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. 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 INC. 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 TextPosition_h +#define TextPosition_h + +#include <wtf/Assertions.h> + +namespace WTF { + +/* + * Text Position + * + * TextPosition structure specifies coordinates within an text resource. It is used mostly + * for saving script source position. + * + * Later TextPosition0 and TextPosition1 and both number types can be merged together quite easily. + * + * 0-based and 1-based + * + * Line and column numbers could be interpreted as zero-based or 1-based. Since + * both practices coexist in WebKit source base, 'int' type should be replaced with + * a dedicated wrapper types, so that compiler helped us with this ambiguity. + * + * Here we introduce 2 types of numbers: ZeroBasedNumber and OneBasedNumber and + * 2 corresponding types of TextPosition structure. While only one type ought to be enough, + * this is done to keep transition to the new types as transparent as possible: + * e.g. in areas where 0-based integers are used, TextPosition0 should be introduced. This + * way all changes will remain trackable. + * + * Later both number types can be merged in one type quite easily. + * + * For type safety and for the future type merge it is important that all operations in API + * that accept or return integer have a name explicitly defining base of integer. For this reason + * int-receiving constructors are hidden from API. + */ + +template<typename NUMBER> +class TextPosition { +public: + TextPosition(NUMBER line, NUMBER column) + : m_line(line) + , m_column(column) + { + } + TextPosition() {} + + // A 'minimum' value of position, used as a default value. + static TextPosition<NUMBER> minimumPosition() { return TextPosition<NUMBER>(NUMBER::base(), NUMBER::base()); } + + // A value with line value less than a minimum; used as an impossible position. + static TextPosition<NUMBER> belowRangePosition() { return TextPosition<NUMBER>(NUMBER::belowBase(), NUMBER::base()); } + + NUMBER m_line; + NUMBER m_column; +}; + +class OneBasedNumber; + +// An int wrapper that always reminds you that the number should be 0-based +class ZeroBasedNumber { +public: + static ZeroBasedNumber fromZeroBasedInt(int zeroBasedInt) { return ZeroBasedNumber(zeroBasedInt); } + + ZeroBasedNumber() {} + + int zeroBasedInt() const { return m_value; } + + OneBasedNumber convertToOneBased() const; + + static ZeroBasedNumber base() { return 0; } + static ZeroBasedNumber belowBase() { return -1; } + +private: + ZeroBasedNumber(int value) : m_value(value) {} + int m_value; +}; + +// An int wrapper that always reminds you that the number should be 1-based +class OneBasedNumber { +public: + static OneBasedNumber fromOneBasedInt(int oneBasedInt) { return OneBasedNumber(oneBasedInt); } + OneBasedNumber() {} + + int oneBasedInt() const { return m_value; } + int convertAsZeroBasedInt() const { return m_value - 1; } + ZeroBasedNumber convertToZeroBased() const { return ZeroBasedNumber::fromZeroBasedInt(m_value - 1); } + + static OneBasedNumber base() { return 1; } + static OneBasedNumber belowBase() { return 0; } + +private: + OneBasedNumber(int value) : m_value(value) {} + int m_value; +}; + +typedef TextPosition<ZeroBasedNumber> TextPosition0; +typedef TextPosition<OneBasedNumber> TextPosition1; + +inline TextPosition0 toZeroBasedTextPosition(const TextPosition1& position) +{ + return TextPosition0(position.m_line.convertToZeroBased(), position.m_column.convertToZeroBased()); +} + +inline TextPosition1 toOneBasedTextPosition(const TextPosition0& position) +{ + return TextPosition1(position.m_line.convertToOneBased(), position.m_column.convertToOneBased()); +} + +inline OneBasedNumber ZeroBasedNumber::convertToOneBased() const +{ + return OneBasedNumber::fromOneBasedInt(m_value + 1); +} + +} + +using WTF::TextPosition0; +using WTF::TextPosition1; + +#endif // TextPosition_h diff --git a/JavaScriptCore/wtf/text/WTFString.cpp b/JavaScriptCore/wtf/text/WTFString.cpp new file mode 100644 index 0000000..6bb74f6 --- /dev/null +++ b/JavaScriptCore/wtf/text/WTFString.cpp @@ -0,0 +1,1003 @@ +/* + * (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 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 <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 std; + +namespace WTF { + +using namespace Unicode; +using namespace std; + +// Construct a string with UTF-16 data. +String::String(const UChar* characters, unsigned length) + : m_impl(characters ? StringImpl::create(characters, length) : 0) +{ +} + +// Construct a string with UTF-16 data, from a null-terminated source. +String::String(const UChar* str) +{ + if (!str) + return; + + size_t len = 0; + while (str[len] != UChar(0)) + len++; + + if (len > numeric_limits<unsigned>::max()) + CRASH(); + + m_impl = StringImpl::create(str, len); +} + +// Construct a string with latin1 data. +String::String(const char* characters, unsigned length) + : m_impl(characters ? StringImpl::create(characters, length) : 0) +{ +} + +// Construct a string with latin1 data, from a null-terminated source. +String::String(const char* characters) + : m_impl(characters ? StringImpl::create(characters) : 0) +{ +} + +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; + if (str.length() > numeric_limits<unsigned>::max() - m_impl->length()) + CRASH(); + 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; + if (m_impl->length() >= numeric_limits<unsigned>::max()) + CRASH(); + 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; + if (m_impl->length() >= numeric_limits<unsigned>::max()) + CRASH(); + 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; +} + +int codePointCompare(const String& a, const String& b) +{ + return codePointCompare(a.impl(), b.impl()); +} + +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; + if (lengthToAppend > numeric_limits<unsigned>::max() - length()) + CRASH(); + 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; + if (lengthToInsert > numeric_limits<unsigned>::max() - length()) + CRASH(); + 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(); +} + +UChar32 String::characterStartingAt(unsigned i) const +{ + if (!m_impl || i >= m_impl->length()) + return 0; + return m_impl->characterStartingAt(i); +} + +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::substringSharingImpl(unsigned offset, unsigned length) const +{ + // FIXME: We used to check against a limit of Heap::minExtraCost / sizeof(UChar). + + unsigned stringLength = this->length(); + offset = min(offset, stringLength); + length = min(length, stringLength - offset); + + if (!offset && length == stringLength) + return *this; + return String(StringImpl::create(m_impl, offset, length)); +} + +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::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); + + QByteArray ba = buffer.toUtf8(); + return StringImpl::create(ba.constData(), ba.length()); + +#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(); +} + +void String::split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const +{ + result.clear(); + + unsigned startPos = 0; + size_t endPos; + while ((endPos = find(separator, startPos)) != notFound) { + if (allowEmptyEntries || startPos != endPos) + result.append(substring(startPos, endPos - startPos)); + startPos = endPos + separator.length(); + } + if (allowEmptyEntries || startPos != 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(); + + unsigned startPos = 0; + size_t endPos; + while ((endPos = find(separator, startPos)) != notFound) { + if (allowEmptyEntries || startPos != endPos) + result.append(substring(startPos, endPos - startPos)); + startPos = endPos + 1; + } + if (allowEmptyEntries || startPos != length()) + result.append(substring(startPos)); +} + +void String::split(UChar separator, Vector<String>& result) const +{ + return split(String(&separator, 1), false, result); +} + +CString String::ascii() 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 && (ch < 0x20 || ch > 0x7f) ? '?' : ch; + } + + return result; +} + +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 > 0xff ? '?' : 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(bool strict) 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). + if (length > numeric_limits<unsigned>::max() / 3) + return CString(); + Vector<char, 1024> bufferVector(length * 3); + + char* buffer = bufferVector.data(); + ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), strict); + ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion + + // Only produced from strict conversion. + if (result == sourceIllegal) + return CString(); + + // Check for an unconverted high surrogate. + if (result == sourceExhausted) { + if (strict) + return CString(); + // This should be one unpaired high surrogate. 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. + ASSERT((characters + 1) == (this->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 (length > numeric_limits<unsigned>::max()) + CRASH(); + + 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 = numeric_limits<IntegralType>::max(); + static const bool isSigned = 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 WTF + +#ifndef NDEBUG +// For use in the debugger +String* string(const char*); +Vector<char> asciiDebug(StringImpl* impl); +Vector<char> asciiDebug(String& string); + +String* string(const char* s) +{ + // leaks memory! + return new String(s); +} + +Vector<char> asciiDebug(StringImpl* impl) +{ + if (!impl) + return asciiDebug(String("[null]").impl()); + + Vector<char> buffer; + unsigned length = impl->length(); + const UChar* characters = impl->characters(); + + buffer.resize(length + 1); + for (unsigned i = 0; i < length; ++i) { + UChar ch = characters[i]; + buffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch; + } + buffer[length] = '\0'; + + return buffer; +} + +Vector<char> asciiDebug(String& string) +{ + return asciiDebug(string.impl()); +} + +#endif diff --git a/JavaScriptCore/wtf/text/WTFString.h b/JavaScriptCore/wtf/text/WTFString.h new file mode 100644 index 0000000..e9d6ae4 --- /dev/null +++ b/JavaScriptCore/wtf/text/WTFString.h @@ -0,0 +1,493 @@ +/* + * (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 + +#if PLATFORM(BREWMP) +// AECHAR is defined in AEEStdDef.h, but don't include it here to avoid conflicts. +#ifndef _AECHAR_DEFINED +typedef uint16 AECHAR; +#define _AECHAR_DEFINED +#endif +#endif + +namespace WTF { + +class CString; +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); + +template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters(const UChar*, size_t); + +class String { +public: + // Construct a null string, distinguishable from an empty string. + String() { } + + // Construct a string with UTF-16 data. + String(const UChar* characters, unsigned length); + + // Construct a string with UTF-16 data, from a null-terminated source. + String(const UChar*); + + // Construct a string with latin1 data. + String(const char* characters, unsigned length); + + // Construct a string with latin1 data, from a null-terminated source. + String(const char* characters); + + // Construct a string referencing an existing StringImpl. + String(StringImpl* impl) : m_impl(impl) { } + String(PassRefPtr<StringImpl> impl) : m_impl(impl) { } + String(RefPtr<StringImpl> impl) : m_impl(impl) { } + + // Inline the destructor. + ALWAYS_INLINE ~String() { } + + void swap(String& o) { m_impl.swap(o.m_impl); } + + static String adopt(StringBuffer& buffer) { return StringImpl::adopt(buffer); } + template<size_t inlineCapacity> + static String adopt(Vector<UChar, inlineCapacity>& vector) { return StringImpl::adopt(vector); } + + bool isNull() const { return !m_impl; } + bool isEmpty() const { return !m_impl || !m_impl->length(); } + + StringImpl* impl() const { return m_impl.get(); } + + unsigned length() const + { + if (!m_impl) + return 0; + return m_impl->length(); + } + + const UChar* characters() const + { + if (!m_impl) + return 0; + return m_impl->characters(); + } + + CString ascii() const; + CString latin1() const; + CString utf8(bool strict = false) const; + + UChar operator[](unsigned index) const + { + if (!m_impl || index >= m_impl->length()) + return 0; + return m_impl->characters()[index]; + } + + 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); + + // Find a single character or string, also with match function & latin1 forms. + size_t find(UChar c, unsigned start = 0) const + { return m_impl ? m_impl->find(c, start) : notFound; } + size_t find(const String& str, unsigned start = 0) const + { return m_impl ? m_impl->find(str.impl(), start) : notFound; } + size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const + { return m_impl ? m_impl->find(matchFunction, start) : notFound; } + size_t find(const char* str, unsigned start = 0) const + { return m_impl ? m_impl->find(str, start) : notFound; } + + // Find the last instance of a single character or string. + size_t reverseFind(UChar c, unsigned start = UINT_MAX) const + { return m_impl ? m_impl->reverseFind(c, start) : notFound; } + size_t reverseFind(const String& str, unsigned start = UINT_MAX) const + { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; } + + // Case insensitive string matching. + size_t findIgnoringCase(const char* str, unsigned start = 0) const + { return m_impl ? m_impl->findIgnoringCase(str, start) : notFound; } + size_t findIgnoringCase(const String& str, unsigned start = 0) const + { return m_impl ? m_impl->findIgnoringCase(str.impl(), start) : notFound; } + size_t reverseFindIgnoringCase(const String& str, unsigned start = UINT_MAX) const + { return m_impl ? m_impl->reverseFindIgnoringCase(str.impl(), start) : notFound; } + + // Wrappers for find & reverseFind adding dynamic sensitivity check. + size_t find(const char* str, unsigned start, bool caseSensitive) const + { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); } + size_t find(const String& str, unsigned start, bool caseSensitive) const + { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); } + size_t reverseFind(const String& str, unsigned start, bool caseSensitive) const + { return caseSensitive ? reverseFind(str, start) : reverseFindIgnoringCase(str, start); } + + const UChar* charactersWithNullTermination(); + + UChar32 characterStartingAt(unsigned) const; // Ditto. + + bool contains(UChar c) const { return find(c) != notFound; } + bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; } + bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; } + + 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 substringSharingImpl(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; + template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const; + + // Return the string with case folded for case insensitive comparison. + String foldCase() const; + +#if !PLATFORM(QT) + static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2); +#else + static String format(const char *, ...); +#endif + + // 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; + +#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 + +#if PLATFORM(BREWMP) + String(const AECHAR*); +#endif + + 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()); } + + // 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(); } + +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); +} + +int codePointCompare(const String&, const String&); + +inline size_t find(const UChar* characters, unsigned length, UChar matchCharacter, unsigned index = 0) +{ + while (index < length) { + if (characters[index] == matchCharacter) + return index; + ++index; + } + return notFound; +} + +inline size_t find(const UChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index = 0) +{ + while (index < length) { + if (matchFunction(characters[index])) + return index; + ++index; + } + return notFound; +} + +inline size_t reverseFind(const UChar* characters, unsigned length, UChar matchCharacter, unsigned index = UINT_MAX) +{ + if (!length) + return notFound; + if (index >= length) + index = length - 1; + while (characters[index] != matchCharacter) { + if (!index--) + return notFound; + } + return index; +} + +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'; + } +} + +template<bool isSpecialCharacter(UChar)> inline bool isAllSpecialCharacters(const UChar* characters, size_t length) +{ + for (size_t i = 0; i < length; ++i) { + if (!isSpecialCharacter(characters[i])) + return false; + } + return true; +} + +template<bool isSpecialCharacter(UChar)> inline bool String::isAllSpecialCharacters() const +{ + return WTF::isAllSpecialCharacters<isSpecialCharacter>(characters(), length()); +} + +// StringHash is the default hash for String +template<typename T> struct DefaultHash; +template<> struct DefaultHash<String> { + typedef StringHash Hash; +}; + +template <> struct VectorTraits<String> : SimpleClassVectorTraits +{ + static const bool canInitializeWithMemset = true; +}; + +} + +using WTF::CString; +using WTF::String; +using WTF::append; +using WTF::appendNumber; +using WTF::charactersAreAllASCII; +using WTF::charactersToIntStrict; +using WTF::charactersToUIntStrict; +using WTF::charactersToInt64Strict; +using WTF::charactersToUInt64Strict; +using WTF::charactersToIntPtrStrict; +using WTF::charactersToInt; +using WTF::charactersToUInt; +using WTF::charactersToInt64; +using WTF::charactersToUInt64; +using WTF::charactersToIntPtr; +using WTF::charactersToDouble; +using WTF::charactersToFloat; +using WTF::equal; +using WTF::equalIgnoringCase; +using WTF::find; +using WTF::isAllSpecialCharacters; +using WTF::isSpaceOrNewline; +using WTF::reverseFind; + +#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/UTF8.cpp b/JavaScriptCore/wtf/unicode/UTF8.cpp index 21d5856..40c5609 100644 --- a/JavaScriptCore/wtf/unicode/UTF8.cpp +++ b/JavaScriptCore/wtf/unicode/UTF8.cpp @@ -240,7 +240,7 @@ ConversionResult convertUTF8ToUTF16( UChar* target = *targetStart; while (source < sourceEnd) { UChar32 ch = 0; - int extraBytesToRead = UTF8SequenceLength(*source) - 1; + int extraBytesToRead = inlineUTF8SequenceLength(*source) - 1; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; diff --git a/JavaScriptCore/wtf/unicode/Unicode.h b/JavaScriptCore/wtf/unicode/Unicode.h index d59439d..50524b1 100644 --- a/JavaScriptCore/wtf/unicode/Unicode.h +++ b/JavaScriptCore/wtf/unicode/Unicode.h @@ -32,7 +32,9 @@ #elif USE(GLIB_UNICODE) #include <wtf/unicode/glib/UnicodeGLib.h> #elif USE(WINCE_UNICODE) -#include <wtf/unicode/wince/UnicodeWince.h> +#include <wtf/unicode/wince/UnicodeWinCE.h> +#elif USE(BREWMP_UNICODE) +#include <wtf/unicode/brew/UnicodeBrew.h> #else #error "Unknown Unicode implementation" #endif diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h b/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h index 5d3eca6..f865ef1 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h +++ b/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h @@ -27,6 +27,7 @@ // some defines from ICU +#define U_IS_BMP(c) ((UChar32)(c)<=0xffff) #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) @@ -35,6 +36,7 @@ #define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0) #define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00) +#define U16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2) #define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800) #define U16_IS_SINGLE(c) !U_IS_SURROGATE(c) diff --git a/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.cpp b/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.cpp new file mode 100644 index 0000000..8367f17 --- /dev/null +++ b/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2006 George Staikos <staikos@kde.org> + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * 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. + */ + +#include "config.h" +#include "UnicodeBrew.h" + +#include <wchar.h> +#include <wctype.h> + +namespace WTF { +namespace Unicode { + +UChar toLower(UChar c) +{ + return towlower(c); +} + +UChar toUpper(UChar c) +{ + return towupper(c); +} + +UChar foldCase(UChar c) +{ + return towlower(c); +} + +bool isPrintableChar(UChar c) +{ + return !!iswprint(c); +} + +bool isUpper(UChar c) +{ + return !!iswupper(c); +} + +bool isLower(UChar c) +{ + return !!iswlower(c); +} + +bool isDigit(UChar c) +{ + return !!iswdigit(c); +} + +bool isPunct(UChar c) +{ + return !!iswpunct(c); +} + +bool isAlphanumeric(UChar c) +{ + return !!iswalnum(c); +} + +int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) +{ + const UChar* sourceIterator = source; + const UChar* sourceEnd = source + sourceLength; + UChar* resultIterator = result; + UChar* resultEnd = result + resultLength; + + if (sourceLength <= resultLength) { + while (sourceIterator < sourceEnd) + *resultIterator++ = towlower(*sourceIterator++); + } else { + while (resultIterator < resultEnd) + *resultIterator++ = towlower(*sourceIterator++); + } + + int remainingCharacters = sourceIterator < sourceEnd ? sourceEnd - sourceIterator : 0; + *isError = !!remainingCharacters; + if (resultIterator < resultEnd) + *resultIterator = 0; + + return (resultIterator - result) + remainingCharacters; +} + +int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) +{ + const UChar* sourceIterator = source; + const UChar* sourceEnd = source + sourceLength; + UChar* resultIterator = result; + UChar* resultEnd = result + resultLength; + + if (sourceLength <= resultLength) { + while (sourceIterator < sourceEnd) + *resultIterator++ = towupper(*sourceIterator++); + } else { + while (resultIterator < resultEnd) + *resultIterator++ = towupper(*sourceIterator++); + } + + int remainingCharacters = sourceIterator < sourceEnd ? sourceEnd - sourceIterator : 0; + *isError = !!remainingCharacters; + if (resultIterator < resultEnd) + *resultIterator = 0; + + return (resultIterator - result) + remainingCharacters; +} + +int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) +{ + *isError = false; + if (resultLength < sourceLength) { + *isError = true; + return sourceLength; + } + for (int i = 0; i < sourceLength; ++i) + result[i] = foldCase(source[i]); + return sourceLength; +} + +UChar toTitleCase(UChar c) +{ + return towupper(c); +} + +Direction direction(UChar32 c) +{ + return static_cast<Direction>(ICU::direction(c)); +} + +CharCategory category(unsigned int c) +{ + return static_cast<CharCategory>(TO_MASK((int8_t) ICU::category(c))); +} + +DecompositionType decompositionType(UChar32 c) +{ + return static_cast<DecompositionType>(ICU::decompositionType(c)); +} + +unsigned char combiningClass(UChar32 c) +{ + return ICU::combiningClass(c); +} + +UChar mirroredChar(UChar32 c) +{ + return ICU::mirroredChar(c); +} + +int digitValue(UChar c) +{ + return ICU::digitValue(c); +} + +bool isSpace(UChar c) +{ + return !!iswspace(c); +} + +bool isLetter(UChar c) +{ + return !!iswalpha(c); +} + +} // namespace Unicode +} // namespace WTF diff --git a/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.h b/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.h new file mode 100644 index 0000000..1d7576f --- /dev/null +++ b/JavaScriptCore/wtf/unicode/brew/UnicodeBrew.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2006 George Staikos <staikos@kde.org> + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2007 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * 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 UnicodeBrew_h +#define UnicodeBrew_h + +#include "UnicodeFromICU.h" +#include "UnicodeMacrosFromICU.h" + +namespace WTF { +namespace Unicode { + +enum Direction { + LeftToRight = ICU::U_LEFT_TO_RIGHT, + RightToLeft = ICU::U_RIGHT_TO_LEFT, + EuropeanNumber = ICU::U_EUROPEAN_NUMBER, + EuropeanNumberSeparator = ICU::U_EUROPEAN_NUMBER_SEPARATOR, + EuropeanNumberTerminator = ICU::U_EUROPEAN_NUMBER_TERMINATOR, + ArabicNumber = ICU::U_ARABIC_NUMBER, + CommonNumberSeparator = ICU::U_COMMON_NUMBER_SEPARATOR, + BlockSeparator = ICU::U_BLOCK_SEPARATOR, + SegmentSeparator = ICU::U_SEGMENT_SEPARATOR, + WhiteSpaceNeutral = ICU::U_WHITE_SPACE_NEUTRAL, + OtherNeutral = ICU::U_OTHER_NEUTRAL, + LeftToRightEmbedding = ICU::U_LEFT_TO_RIGHT_EMBEDDING, + LeftToRightOverride = ICU::U_LEFT_TO_RIGHT_OVERRIDE, + RightToLeftArabic = ICU::U_RIGHT_TO_LEFT_ARABIC, + RightToLeftEmbedding = ICU::U_RIGHT_TO_LEFT_EMBEDDING, + RightToLeftOverride = ICU::U_RIGHT_TO_LEFT_OVERRIDE, + PopDirectionalFormat = ICU::U_POP_DIRECTIONAL_FORMAT, + NonSpacingMark = ICU::U_DIR_NON_SPACING_MARK, + BoundaryNeutral = ICU::U_BOUNDARY_NEUTRAL +}; + +enum DecompositionType { + DecompositionNone = ICU::U_DT_NONE, + DecompositionCanonical = ICU::U_DT_CANONICAL, + DecompositionCompat = ICU::U_DT_COMPAT, + DecompositionCircle = ICU::U_DT_CIRCLE, + DecompositionFinal = ICU::U_DT_FINAL, + DecompositionFont = ICU::U_DT_FONT, + DecompositionFraction = ICU::U_DT_FRACTION, + DecompositionInitial = ICU::U_DT_INITIAL, + DecompositionIsolated = ICU::U_DT_ISOLATED, + DecompositionMedial = ICU::U_DT_MEDIAL, + DecompositionNarrow = ICU::U_DT_NARROW, + DecompositionNoBreak = ICU::U_DT_NOBREAK, + DecompositionSmall = ICU::U_DT_SMALL, + DecompositionSquare = ICU::U_DT_SQUARE, + DecompositionSub = ICU::U_DT_SUB, + DecompositionSuper = ICU::U_DT_SUPER, + DecompositionVertical = ICU::U_DT_VERTICAL, + DecompositionWide = ICU::U_DT_WIDE, +}; + +enum CharCategory { + NoCategory = 0, + Other_NotAssigned = TO_MASK(ICU::U_GENERAL_OTHER_TYPES), + Letter_Uppercase = TO_MASK(ICU::U_UPPERCASE_LETTER), + Letter_Lowercase = TO_MASK(ICU::U_LOWERCASE_LETTER), + Letter_Titlecase = TO_MASK(ICU::U_TITLECASE_LETTER), + Letter_Modifier = TO_MASK(ICU::U_MODIFIER_LETTER), + Letter_Other = TO_MASK(ICU::U_OTHER_LETTER), + + Mark_NonSpacing = TO_MASK(ICU::U_NON_SPACING_MARK), + Mark_Enclosing = TO_MASK(ICU::U_ENCLOSING_MARK), + Mark_SpacingCombining = TO_MASK(ICU::U_COMBINING_SPACING_MARK), + + Number_DecimalDigit = TO_MASK(ICU::U_DECIMAL_DIGIT_NUMBER), + Number_Letter = TO_MASK(ICU::U_LETTER_NUMBER), + Number_Other = TO_MASK(ICU::U_OTHER_NUMBER), + + Separator_Space = TO_MASK(ICU::U_SPACE_SEPARATOR), + Separator_Line = TO_MASK(ICU::U_LINE_SEPARATOR), + Separator_Paragraph = TO_MASK(ICU::U_PARAGRAPH_SEPARATOR), + + Other_Control = TO_MASK(ICU::U_CONTROL_CHAR), + Other_Format = TO_MASK(ICU::U_FORMAT_CHAR), + Other_PrivateUse = TO_MASK(ICU::U_PRIVATE_USE_CHAR), + Other_Surrogate = TO_MASK(ICU::U_SURROGATE), + + Punctuation_Dash = TO_MASK(ICU::U_DASH_PUNCTUATION), + Punctuation_Open = TO_MASK(ICU::U_START_PUNCTUATION), + Punctuation_Close = TO_MASK(ICU::U_END_PUNCTUATION), + Punctuation_Connector = TO_MASK(ICU::U_CONNECTOR_PUNCTUATION), + Punctuation_Other = TO_MASK(ICU::U_OTHER_PUNCTUATION), + + Symbol_Math = TO_MASK(ICU::U_MATH_SYMBOL), + Symbol_Currency = TO_MASK(ICU::U_CURRENCY_SYMBOL), + Symbol_Modifier = TO_MASK(ICU::U_MODIFIER_SYMBOL), + Symbol_Other = TO_MASK(ICU::U_OTHER_SYMBOL), + + Punctuation_InitialQuote = TO_MASK(ICU::U_INITIAL_PUNCTUATION), + Punctuation_FinalQuote = TO_MASK(ICU::U_FINAL_PUNCTUATION) +}; + +UChar foldCase(UChar); + +int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); + +int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); + +UChar toUpper(UChar); +UChar toLower(UChar); + +bool isUpper(UChar); + +int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); + +UChar toTitleCase(UChar); + +inline bool isArabicChar(UChar32 c) +{ + return c >= 0x0600 && c <= 0x06FF; +} + +bool isAlphanumeric(UChar); + +CharCategory category(unsigned int); + +inline bool isSeparatorSpace(UChar c) +{ + return category(c) == Separator_Space; +} + +bool isPrintableChar(UChar); + +bool isDigit(UChar); + +bool isPunct(UChar); + +inline bool hasLineBreakingPropertyComplexContext(UChar32) +{ + // FIXME: implement! + return false; +} + +inline bool hasLineBreakingPropertyComplexContextOrIdeographic(UChar32 c) +{ + // FIXME + return false; +} + +UChar mirroredChar(UChar32); + +Direction direction(UChar32); + +bool isLower(UChar); + +int digitValue(UChar); + +unsigned char combiningClass(UChar32); + +DecompositionType decompositionType(UChar32); + +inline int umemcasecmp(const UChar* a, const UChar* b, int len) +{ + for (int i = 0; i < len; ++i) { + UChar c1 = foldCase(a[i]); + UChar c2 = foldCase(b[i]); + if (c1 != c2) + return c1 - c2; + } + return 0; +} + +bool isSpace(UChar); +bool isLetter(UChar); + +} // namespace Unicode +} // namespace WTF + +#endif diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp index e20c376..a01c3ee 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp +++ b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Jürg Billeter <j@bitron.ch> * Copyright (C) 2008 Dominik Röttsches <dominik.roettsches@access-company.com> + * Copyright (C) 2010 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,6 +23,11 @@ #include "config.h" #include "UnicodeGLib.h" +#include <wtf/Vector.h> +#include <wtf/unicode/UTF8.h> + +#define UTF8_IS_SURROGATE(character) (character >= 0x10000 && character <= 0x10FFFF) + namespace WTF { namespace Unicode { @@ -43,100 +49,71 @@ UChar32 foldCase(UChar32 ch) return *ucs4Result; } -int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +static int getUTF16LengthFromUTF8(const gchar* utf8String, int length) { - *error = false; - GOwnPtr<GError> gerror; + int utf16Length = 0; + const gchar* inputString = utf8String; - GOwnPtr<char> utf8src; - utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr())); - if (gerror) { - *error = true; - return -1; - } - - GOwnPtr<char> utf8result; - utf8result.set(g_utf8_casefold(utf8src.get(), -1)); + while ((utf8String + length - inputString > 0) && *inputString) { + gunichar character = g_utf8_get_char(inputString); - long utf16resultLength = -1; - GOwnPtr<UChar> utf16result; - utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr())); - if (gerror) { - *error = true; - return -1; + utf16Length += UTF8_IS_SURROGATE(character) ? 2 : 1; + inputString = g_utf8_next_char(inputString); } - if (utf16resultLength > resultLength) { - *error = true; - return utf16resultLength; - } - memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar)); - - return utf16resultLength; + return utf16Length; } -int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +typedef gchar* (*UTF8CaseFunction)(const gchar*, gssize length); + +static int convertCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error, UTF8CaseFunction caseFunction) { *error = false; - GOwnPtr<GError> gerror; - GOwnPtr<char> utf8src; - utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr())); - if (gerror) { + // Allocate a buffer big enough to hold all the characters. + Vector<char> buffer(srcLength * 3); + char* utf8Target = buffer.data(); + const UChar* utf16Source = src; + ConversionResult conversionResult = convertUTF16ToUTF8(&utf16Source, utf16Source + srcLength, &utf8Target, utf8Target + buffer.size(), true); + if (conversionResult != conversionOK) { *error = true; return -1; } + buffer.shrink(utf8Target - buffer.data()); - GOwnPtr<char> utf8result; - utf8result.set(g_utf8_strdown(utf8src.get(), -1)); + GOwnPtr<char> utf8Result(caseFunction(buffer.data(), buffer.size())); + long utf8ResultLength = strlen(utf8Result.get()); - long utf16resultLength = -1; - GOwnPtr<UChar> utf16result; - utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr())); - if (gerror) { + // Calculate the destination buffer size. + int realLength = getUTF16LengthFromUTF8(utf8Result.get(), utf8ResultLength); + if (realLength > resultLength) { *error = true; - return -1; + return realLength; } - if (utf16resultLength > resultLength) { + // Convert the result to UTF-16. + UChar* utf16Target = result; + const char* utf8Source = utf8Result.get(); + conversionResult = convertUTF8ToUTF16(&utf8Source, utf8Source + utf8ResultLength, &utf16Target, utf16Target + resultLength, true); + long utf16ResultLength = utf16Target - result; + if (conversionResult != conversionOK) *error = true; - return utf16resultLength; - } - memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar)); - return utf16resultLength; + return utf16ResultLength <= 0 ? -1 : utf16ResultLength; } - -int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) { - *error = false; - GOwnPtr<GError> gerror; - - GOwnPtr<char> utf8src; - utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr())); - if (gerror) { - *error = true; - return -1; - } - - GOwnPtr<char> utf8result; - utf8result.set(g_utf8_strup(utf8src.get(), -1)); - - long utf16resultLength = -1; - GOwnPtr<UChar> utf16result; - utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr())); - if (gerror) { - *error = true; - return -1; - } + return convertCase(result, resultLength, src, srcLength, error, g_utf8_casefold); +} - if (utf16resultLength > resultLength) { - *error = true; - return utf16resultLength; - } - memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar)); +int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +{ + return convertCase(result, resultLength, src, srcLength, error, g_utf8_strdown); +} - return utf16resultLength; +int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +{ + return convertCase(result, resultLength, src, srcLength, error, g_utf8_strup); } Direction direction(UChar32 c) 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..805b114 100644 --- a/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp +++ b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp @@ -57,11 +57,11 @@ 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. -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !OS(IPHONE_OS) +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !OS(IOS) RetainPtr<CFLocaleRef> currentLocale(AdoptCF, CFLocaleCopyCurrent()); CFStringRef collationOrder = (CFStringRef)CFLocaleGetValue(currentLocale.get(), kCFLocaleCollatorIdentifier); #else @@ -69,13 +69,12 @@ std::auto_ptr<Collator> Collator::userDefault() CFStringRef collationOrder = collationOrderRetainer.get(); #endif char buf[256]; - if (collationOrder) { - CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII); - return std::auto_ptr<Collator>(new Collator(buf)); - } else - return std::auto_ptr<Collator>(new Collator("")); + if (!collationOrder) + return adoptPtr(new Collator("")); + CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII); + return adoptPtr(new Collator(buf)); #else - return std::auto_ptr<Collator>(new Collator(0)); + return adoptPtr(new Collator(0)); #endif } diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index 9b1754a..eaa7a07 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -23,12 +23,17 @@ #ifndef WTF_UNICODE_QT4_H #define WTF_UNICODE_QT4_H +#include "UnicodeMacrosFromICU.h" + #include <QChar> #include <QString> #include <config.h> #include <stdint.h> +#if USE(QT_ICU_TEXT_BREAKING) +#include <unicode/ubrk.h> +#endif QT_BEGIN_NAMESPACE namespace QUnicodeTables { @@ -56,52 +61,15 @@ 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(LINUX)) typedef wchar_t UChar; #else typedef uint16_t UChar; #endif -typedef uint32_t UChar32; - -// some defines from ICU - -#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) -#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) -#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) -#define U16_GET_SUPPLEMENTARY(lead, trail) \ - (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET) - -#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0) -#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00) - -#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800) -#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c) -#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c) -#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0) - -#define U16_NEXT(s, i, length, c) { \ - (c)=(s)[(i)++]; \ - if(U16_IS_LEAD(c)) { \ - uint16_t __c2; \ - if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \ - ++(i); \ - (c)=U16_GET_SUPPLEMENTARY((c), __c2); \ - } \ - } \ -} -#define U16_PREV(s, start, i, c) { \ - (c)=(s)[--(i)]; \ - if(U16_IS_TRAIL(c)) { \ - uint16_t __c2; \ - if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \ - --(i); \ - (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \ - } \ - } \ -} - -#define U_MASK(x) ((uint32_t)1<<(x)) +#if !USE(QT_ICU_TEXT_BREAKING) +typedef uint32_t UChar32; +#endif namespace WTF { namespace Unicode { @@ -188,7 +156,7 @@ enum CharCategory { inline UChar32 toLower(UChar32 ch) { - return QChar::toLower(ch); + return QChar::toLower(uint32_t(ch)); } inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) @@ -244,9 +212,9 @@ inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLen return rindex + needed; } -inline UChar32 toUpper(UChar32 ch) +inline UChar32 toUpper(UChar32 c) { - return QChar::toUpper(ch); + return QChar::toUpper(uint32_t(c)); } inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) @@ -304,12 +272,12 @@ inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLen inline int toTitleCase(UChar32 c) { - return QChar::toTitleCase(c); + return QChar::toTitleCase(uint32_t(c)); } inline UChar32 foldCase(UChar32 c) { - return QChar::toCaseFolded(c); + return QChar::toCaseFolded(uint32_t(c)); } inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) @@ -334,12 +302,12 @@ inline bool isPrintableChar(UChar32 c) { const uint test = U_MASK(QChar::Other_Control) | U_MASK(QChar::Other_NotAssigned); - return !(U_MASK(QChar::category(c)) & test); + return !(U_MASK(QChar::category(uint32_t(c))) & test); } inline bool isSeparatorSpace(UChar32 c) { - return QChar::category(c) == QChar::Separator_Space; + return QChar::category(uint32_t(c)) == QChar::Separator_Space; } inline bool isPunct(UChar32 c) @@ -351,12 +319,12 @@ inline bool isPunct(UChar32 c) U_MASK(QChar::Punctuation_InitialQuote) | U_MASK(QChar::Punctuation_FinalQuote) | U_MASK(QChar::Punctuation_Other); - return U_MASK(QChar::category(c)) & test; + return U_MASK(QChar::category(uint32_t(c))) & test; } inline bool isLower(UChar32 c) { - return QChar::category(c) == QChar::Letter_Lowercase; + return QChar::category(uint32_t(c)) == QChar::Letter_Lowercase; } inline bool hasLineBreakingPropertyComplexContext(UChar32) @@ -367,12 +335,12 @@ inline bool hasLineBreakingPropertyComplexContext(UChar32) inline UChar32 mirroredChar(UChar32 c) { - return QChar::mirroredChar(c); + return QChar::mirroredChar(uint32_t(c)); } inline uint8_t combiningClass(UChar32 c) { - return QChar::combiningClass(c); + return QChar::combiningClass(uint32_t(c)); } inline DecompositionType decompositionType(UChar32 c) @@ -394,12 +362,12 @@ inline int umemcasecmp(const UChar* a, const UChar* b, int len) inline Direction direction(UChar32 c) { - return (Direction)QChar::direction(c); + return (Direction)QChar::direction(uint32_t(c)); } inline CharCategory category(UChar32 c) { - return (CharCategory) U_MASK(QChar::category(c)); + return (CharCategory) U_MASK(QChar::category(uint32_t(c))); } } } diff --git a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp b/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.cpp index 2df44f8..96dac7d 100644 --- a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp +++ b/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.cpp @@ -20,64 +20,69 @@ */ #include "config.h" -#include "UnicodeWince.h" +#include "UnicodeWinCE.h" #include <wchar.h> namespace WTF { namespace Unicode { -wchar_t toLower(wchar_t c) +UChar toLower(UChar c) { return towlower(c); } -wchar_t toUpper(wchar_t c) +UChar toUpper(UChar c) { return towupper(c); } -wchar_t foldCase(wchar_t c) +UChar foldCase(UChar c) { return towlower(c); } -bool isPrintableChar(wchar_t c) +bool isPrintableChar(UChar c) { return !!iswprint(c); } -bool isSpace(wchar_t c) +bool isSpace(UChar c) { return !!iswspace(c); } -bool isLetter(wchar_t c) +bool isLetter(UChar c) { return !!iswalpha(c); } -bool isUpper(wchar_t c) +bool isUpper(UChar c) { return !!iswupper(c); } -bool isLower(wchar_t c) +bool isLower(UChar c) { return !!iswlower(c); } -bool isDigit(wchar_t c) +bool isDigit(UChar c) { return !!iswdigit(c); } -bool isPunct(wchar_t c) +bool isPunct(UChar c) { return !!iswpunct(c); } -int toLower(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError) +bool isAlphanumeric(UChar c) +{ + return !!iswalnum(c); +} + +int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) { const UChar* sourceIterator = source; const UChar* sourceEnd = source + sourceLength; @@ -94,14 +99,14 @@ int toLower(wchar_t* result, int resultLength, const wchar_t* source, int source if (sourceIterator < sourceEnd) remainingCharacters += sourceEnd - sourceIterator; - *isError = (remainingCharacters != 0); + *isError = !!remainingCharacters; if (resultIterator < resultEnd) *resultIterator = 0; return (resultIterator - result) + remainingCharacters; } -int toUpper(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError) +int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) { const UChar* sourceIterator = source; const UChar* sourceEnd = source + sourceLength; @@ -118,14 +123,14 @@ int toUpper(wchar_t* result, int resultLength, const wchar_t* source, int source if (sourceIterator < sourceEnd) remainingCharacters += sourceEnd - sourceIterator; - *isError = (remainingCharacters != 0); + *isError = !!remainingCharacters; if (resultIterator < resultEnd) *resultIterator = 0; return (resultIterator - result) + remainingCharacters; } -int foldCase(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError) +int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError) { *isError = false; if (resultLength < sourceLength) { @@ -137,7 +142,7 @@ int foldCase(wchar_t* result, int resultLength, const wchar_t* source, int sourc return sourceLength; } -wchar_t toTitleCase(wchar_t c) +UChar toTitleCase(UChar c) { return towupper(c); } @@ -162,12 +167,12 @@ unsigned char combiningClass(UChar32 c) return UnicodeCE::combiningClass(c); } -wchar_t mirroredChar(UChar32 c) +UChar mirroredChar(UChar32 c) { return UnicodeCE::mirroredChar(c); } -int digitValue(wchar_t c) +int digitValue(UChar c) { return UnicodeCE::digitValue(c); } diff --git a/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h b/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h new file mode 100644 index 0000000..2688aa9 --- /dev/null +++ b/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006 George Staikos <staikos@kde.org> + * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> + * Copyright (C) 2007 Apple Computer, 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. + * + */ + +#ifndef WTF_UnicodeWinCE_h +#define WTF_UnicodeWinCE_h + +#include "UnicodeMacrosFromICU.h" + +#include "ce_unicode.h" + +#define TO_MASK(x) (1 << (x)) + +namespace WTF { +namespace Unicode { + +enum Direction { + LeftToRight = UnicodeCE::U_LEFT_TO_RIGHT, + RightToLeft = UnicodeCE::U_RIGHT_TO_LEFT, + EuropeanNumber = UnicodeCE::U_EUROPEAN_NUMBER, + EuropeanNumberSeparator = UnicodeCE::U_EUROPEAN_NUMBER_SEPARATOR, + EuropeanNumberTerminator = UnicodeCE::U_EUROPEAN_NUMBER_TERMINATOR, + ArabicNumber = UnicodeCE::U_ARABIC_NUMBER, + CommonNumberSeparator = UnicodeCE::U_COMMON_NUMBER_SEPARATOR, + BlockSeparator = UnicodeCE::U_BLOCK_SEPARATOR, + SegmentSeparator = UnicodeCE::U_SEGMENT_SEPARATOR, + WhiteSpaceNeutral = UnicodeCE::U_WHITE_SPACE_NEUTRAL, + OtherNeutral = UnicodeCE::U_OTHER_NEUTRAL, + LeftToRightEmbedding = UnicodeCE::U_LEFT_TO_RIGHT_EMBEDDING, + LeftToRightOverride = UnicodeCE::U_LEFT_TO_RIGHT_OVERRIDE, + RightToLeftArabic = UnicodeCE::U_RIGHT_TO_LEFT_ARABIC, + RightToLeftEmbedding = UnicodeCE::U_RIGHT_TO_LEFT_EMBEDDING, + RightToLeftOverride = UnicodeCE::U_RIGHT_TO_LEFT_OVERRIDE, + PopDirectionalFormat = UnicodeCE::U_POP_DIRECTIONAL_FORMAT, + NonSpacingMark = UnicodeCE::U_DIR_NON_SPACING_MARK, + BoundaryNeutral = UnicodeCE::U_BOUNDARY_NEUTRAL +}; + +enum DecompositionType { + DecompositionNone = UnicodeCE::U_DT_NONE, + DecompositionCanonical = UnicodeCE::U_DT_CANONICAL, + DecompositionCompat = UnicodeCE::U_DT_COMPAT, + DecompositionCircle = UnicodeCE::U_DT_CIRCLE, + DecompositionFinal = UnicodeCE::U_DT_FINAL, + DecompositionFont = UnicodeCE::U_DT_FONT, + DecompositionFraction = UnicodeCE::U_DT_FRACTION, + DecompositionInitial = UnicodeCE::U_DT_INITIAL, + DecompositionIsolated = UnicodeCE::U_DT_ISOLATED, + DecompositionMedial = UnicodeCE::U_DT_MEDIAL, + DecompositionNarrow = UnicodeCE::U_DT_NARROW, + DecompositionNoBreak = UnicodeCE::U_DT_NOBREAK, + DecompositionSmall = UnicodeCE::U_DT_SMALL, + DecompositionSquare = UnicodeCE::U_DT_SQUARE, + DecompositionSub = UnicodeCE::U_DT_SUB, + DecompositionSuper = UnicodeCE::U_DT_SUPER, + DecompositionVertical = UnicodeCE::U_DT_VERTICAL, + DecompositionWide = UnicodeCE::U_DT_WIDE +}; + +enum CharCategory { + NoCategory = 0, + Other_NotAssigned = TO_MASK(UnicodeCE::U_GENERAL_OTHER_TYPES), + Letter_Uppercase = TO_MASK(UnicodeCE::U_UPPERCASE_LETTER), + Letter_Lowercase = TO_MASK(UnicodeCE::U_LOWERCASE_LETTER), + Letter_Titlecase = TO_MASK(UnicodeCE::U_TITLECASE_LETTER), + Letter_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_LETTER), + Letter_Other = TO_MASK(UnicodeCE::U_OTHER_LETTER), + + Mark_NonSpacing = TO_MASK(UnicodeCE::U_NON_SPACING_MARK), + Mark_Enclosing = TO_MASK(UnicodeCE::U_ENCLOSING_MARK), + Mark_SpacingCombining = TO_MASK(UnicodeCE::U_COMBINING_SPACING_MARK), + + Number_DecimalDigit = TO_MASK(UnicodeCE::U_DECIMAL_DIGIT_NUMBER), + Number_Letter = TO_MASK(UnicodeCE::U_LETTER_NUMBER), + Number_Other = TO_MASK(UnicodeCE::U_OTHER_NUMBER), + + Separator_Space = TO_MASK(UnicodeCE::U_SPACE_SEPARATOR), + Separator_Line = TO_MASK(UnicodeCE::U_LINE_SEPARATOR), + Separator_Paragraph = TO_MASK(UnicodeCE::U_PARAGRAPH_SEPARATOR), + + Other_Control = TO_MASK(UnicodeCE::U_CONTROL_CHAR), + Other_Format = TO_MASK(UnicodeCE::U_FORMAT_CHAR), + Other_PrivateUse = TO_MASK(UnicodeCE::U_PRIVATE_USE_CHAR), + Other_Surrogate = TO_MASK(UnicodeCE::U_SURROGATE), + + Punctuation_Dash = TO_MASK(UnicodeCE::U_DASH_PUNCTUATION), + Punctuation_Open = TO_MASK(UnicodeCE::U_START_PUNCTUATION), + Punctuation_Close = TO_MASK(UnicodeCE::U_END_PUNCTUATION), + Punctuation_Connector = TO_MASK(UnicodeCE::U_CONNECTOR_PUNCTUATION), + Punctuation_Other = TO_MASK(UnicodeCE::U_OTHER_PUNCTUATION), + + Symbol_Math = TO_MASK(UnicodeCE::U_MATH_SYMBOL), + Symbol_Currency = TO_MASK(UnicodeCE::U_CURRENCY_SYMBOL), + Symbol_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_SYMBOL), + Symbol_Other = TO_MASK(UnicodeCE::U_OTHER_SYMBOL), + + Punctuation_InitialQuote = TO_MASK(UnicodeCE::U_INITIAL_PUNCTUATION), + Punctuation_FinalQuote = TO_MASK(UnicodeCE::U_FINAL_PUNCTUATION) +}; + +CharCategory category(unsigned int); + +bool isSpace(UChar); +bool isLetter(UChar); +bool isPrintableChar(UChar); +bool isUpper(UChar); +bool isLower(UChar); +bool isPunct(UChar); +bool isDigit(UChar); +bool isAlphanumeric(UChar); +inline bool isSeparatorSpace(UChar c) { return category(c) == Separator_Space; } +inline bool isHighSurrogate(UChar c) { return (c & 0xfc00) == 0xd800; } +inline bool isLowSurrogate(UChar c) { return (c & 0xfc00) == 0xdc00; } + +UChar toLower(UChar); +UChar toUpper(UChar); +UChar foldCase(UChar); +UChar toTitleCase(UChar); +int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); +int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); +int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError); + +int digitValue(UChar); + +UChar mirroredChar(UChar32); +unsigned char combiningClass(UChar32); +DecompositionType decompositionType(UChar32); +Direction direction(UChar32); +inline bool isArabicChar(UChar32 c) +{ + return c >= 0x0600 && c <= 0x06FF; +} + +inline bool hasLineBreakingPropertyComplexContext(UChar32) +{ + return false; // FIXME: implement! +} + +inline int umemcasecmp(const UChar* a, const UChar* b, int len) +{ + for (int i = 0; i < len; ++i) { + UChar c1 = foldCase(a[i]); + UChar c2 = foldCase(b[i]); + if (c1 != c2) + return c1 - c2; + } + return 0; +} + +inline UChar32 surrogateToUcs4(UChar high, UChar low) +{ + return (UChar32(high) << 10) + low - 0x35fdc00; +} + +} // namespace Unicode +} // namespace WTF + +#endif // WTF_UnicodeWinCE_h diff --git a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h b/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h deleted file mode 100644 index db656ec..0000000 --- a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2006 George Staikos <staikos@kde.org> - * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> - * Copyright (C) 2007 Apple Computer, 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. - * - */ - -#ifndef UNICODE_WINCE_H -#define UNICODE_WINCE_H - -#include "ce_unicode.h" - -#define TO_MASK(x) (1 << (x)) - -// some defines from ICU needed one or two places - -#define U16_IS_LEAD(c) (((c) & 0xfffffc00) == 0xd800) -#define U16_IS_TRAIL(c) (((c) & 0xfffffc00) == 0xdc00) -#define U16_SURROGATE_OFFSET ((0xd800 << 10UL) + 0xdc00 - 0x10000) -#define U16_GET_SUPPLEMENTARY(lead, trail) \ - (((UChar32)(lead) << 10UL) + (UChar32)(trail) - U16_SURROGATE_OFFSET) - -#define U16_LEAD(supplementary) (UChar)(((supplementary) >> 10) + 0xd7c0) -#define U16_TRAIL(supplementary) (UChar)(((supplementary) & 0x3ff) | 0xdc00) - -#define U_IS_SURROGATE(c) (((c) & 0xfffff800) == 0xd800) -#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c) -#define U16_IS_SURROGATE_LEAD(c) (((c) & 0x400) == 0) - -#define U16_NEXT(s, i, length, c) { \ - (c)=(s)[(i)++]; \ - if (U16_IS_LEAD(c)) { \ - uint16_t __c2; \ - if ((i) < (length) && U16_IS_TRAIL(__c2 = (s)[(i)])) { \ - ++(i); \ - (c) = U16_GET_SUPPLEMENTARY((c), __c2); \ - } \ - } \ -} - -#define U16_PREV(s, start, i, c) { \ - (c)=(s)[--(i)]; \ - if (U16_IS_TRAIL(c)) { \ - uint16_t __c2; \ - if ((i) > (start) && U16_IS_LEAD(__c2 = (s)[(i) - 1])) { \ - --(i); \ - (c) = U16_GET_SUPPLEMENTARY(__c2, (c)); \ - } \ - } \ -} - -#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c) - -namespace WTF { - - namespace Unicode { - - enum Direction { - LeftToRight = UnicodeCE::U_LEFT_TO_RIGHT, - RightToLeft = UnicodeCE::U_RIGHT_TO_LEFT, - EuropeanNumber = UnicodeCE::U_EUROPEAN_NUMBER, - EuropeanNumberSeparator = UnicodeCE::U_EUROPEAN_NUMBER_SEPARATOR, - EuropeanNumberTerminator = UnicodeCE::U_EUROPEAN_NUMBER_TERMINATOR, - ArabicNumber = UnicodeCE::U_ARABIC_NUMBER, - CommonNumberSeparator = UnicodeCE::U_COMMON_NUMBER_SEPARATOR, - BlockSeparator = UnicodeCE::U_BLOCK_SEPARATOR, - SegmentSeparator = UnicodeCE::U_SEGMENT_SEPARATOR, - WhiteSpaceNeutral = UnicodeCE::U_WHITE_SPACE_NEUTRAL, - OtherNeutral = UnicodeCE::U_OTHER_NEUTRAL, - LeftToRightEmbedding = UnicodeCE::U_LEFT_TO_RIGHT_EMBEDDING, - LeftToRightOverride = UnicodeCE::U_LEFT_TO_RIGHT_OVERRIDE, - RightToLeftArabic = UnicodeCE::U_RIGHT_TO_LEFT_ARABIC, - RightToLeftEmbedding = UnicodeCE::U_RIGHT_TO_LEFT_EMBEDDING, - RightToLeftOverride = UnicodeCE::U_RIGHT_TO_LEFT_OVERRIDE, - PopDirectionalFormat = UnicodeCE::U_POP_DIRECTIONAL_FORMAT, - NonSpacingMark = UnicodeCE::U_DIR_NON_SPACING_MARK, - BoundaryNeutral = UnicodeCE::U_BOUNDARY_NEUTRAL - }; - - enum DecompositionType { - DecompositionNone = UnicodeCE::U_DT_NONE, - DecompositionCanonical = UnicodeCE::U_DT_CANONICAL, - DecompositionCompat = UnicodeCE::U_DT_COMPAT, - DecompositionCircle = UnicodeCE::U_DT_CIRCLE, - DecompositionFinal = UnicodeCE::U_DT_FINAL, - DecompositionFont = UnicodeCE::U_DT_FONT, - DecompositionFraction = UnicodeCE::U_DT_FRACTION, - DecompositionInitial = UnicodeCE::U_DT_INITIAL, - DecompositionIsolated = UnicodeCE::U_DT_ISOLATED, - DecompositionMedial = UnicodeCE::U_DT_MEDIAL, - DecompositionNarrow = UnicodeCE::U_DT_NARROW, - DecompositionNoBreak = UnicodeCE::U_DT_NOBREAK, - DecompositionSmall = UnicodeCE::U_DT_SMALL, - DecompositionSquare = UnicodeCE::U_DT_SQUARE, - DecompositionSub = UnicodeCE::U_DT_SUB, - DecompositionSuper = UnicodeCE::U_DT_SUPER, - DecompositionVertical = UnicodeCE::U_DT_VERTICAL, - DecompositionWide = UnicodeCE::U_DT_WIDE, - }; - - enum CharCategory { - NoCategory = 0, - Other_NotAssigned = TO_MASK(UnicodeCE::U_GENERAL_OTHER_TYPES), - Letter_Uppercase = TO_MASK(UnicodeCE::U_UPPERCASE_LETTER), - Letter_Lowercase = TO_MASK(UnicodeCE::U_LOWERCASE_LETTER), - Letter_Titlecase = TO_MASK(UnicodeCE::U_TITLECASE_LETTER), - Letter_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_LETTER), - Letter_Other = TO_MASK(UnicodeCE::U_OTHER_LETTER), - - Mark_NonSpacing = TO_MASK(UnicodeCE::U_NON_SPACING_MARK), - Mark_Enclosing = TO_MASK(UnicodeCE::U_ENCLOSING_MARK), - Mark_SpacingCombining = TO_MASK(UnicodeCE::U_COMBINING_SPACING_MARK), - - Number_DecimalDigit = TO_MASK(UnicodeCE::U_DECIMAL_DIGIT_NUMBER), - Number_Letter = TO_MASK(UnicodeCE::U_LETTER_NUMBER), - Number_Other = TO_MASK(UnicodeCE::U_OTHER_NUMBER), - - Separator_Space = TO_MASK(UnicodeCE::U_SPACE_SEPARATOR), - Separator_Line = TO_MASK(UnicodeCE::U_LINE_SEPARATOR), - Separator_Paragraph = TO_MASK(UnicodeCE::U_PARAGRAPH_SEPARATOR), - - Other_Control = TO_MASK(UnicodeCE::U_CONTROL_CHAR), - Other_Format = TO_MASK(UnicodeCE::U_FORMAT_CHAR), - Other_PrivateUse = TO_MASK(UnicodeCE::U_PRIVATE_USE_CHAR), - Other_Surrogate = TO_MASK(UnicodeCE::U_SURROGATE), - - Punctuation_Dash = TO_MASK(UnicodeCE::U_DASH_PUNCTUATION), - Punctuation_Open = TO_MASK(UnicodeCE::U_START_PUNCTUATION), - Punctuation_Close = TO_MASK(UnicodeCE::U_END_PUNCTUATION), - Punctuation_Connector = TO_MASK(UnicodeCE::U_CONNECTOR_PUNCTUATION), - Punctuation_Other = TO_MASK(UnicodeCE::U_OTHER_PUNCTUATION), - - Symbol_Math = TO_MASK(UnicodeCE::U_MATH_SYMBOL), - Symbol_Currency = TO_MASK(UnicodeCE::U_CURRENCY_SYMBOL), - Symbol_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_SYMBOL), - Symbol_Other = TO_MASK(UnicodeCE::U_OTHER_SYMBOL), - - Punctuation_InitialQuote = TO_MASK(UnicodeCE::U_INITIAL_PUNCTUATION), - Punctuation_FinalQuote = TO_MASK(UnicodeCE::U_FINAL_PUNCTUATION) - }; - - CharCategory category(unsigned int); - - bool isSpace(wchar_t); - bool isLetter(wchar_t); - bool isPrintableChar(wchar_t); - bool isUpper(wchar_t); - bool isLower(wchar_t); - bool isPunct(wchar_t); - bool isDigit(wchar_t); - inline bool isSeparatorSpace(wchar_t c) { return category(c) == Separator_Space; } - inline bool isHighSurrogate(wchar_t c) { return (c & 0xfc00) == 0xd800; } - inline bool isLowSurrogate(wchar_t c) { return (c & 0xfc00) == 0xdc00; } - - wchar_t toLower(wchar_t); - wchar_t toUpper(wchar_t); - wchar_t foldCase(wchar_t); - wchar_t toTitleCase(wchar_t); - int toLower(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError); - int toUpper(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError); - int foldCase(UChar* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError); - - int digitValue(wchar_t); - - wchar_t mirroredChar(UChar32); - unsigned char combiningClass(UChar32); - DecompositionType decompositionType(UChar32); - Direction direction(UChar32); - inline bool isArabicChar(UChar32) - { - return false; // FIXME: implement! - } - - inline bool hasLineBreakingPropertyComplexContext(UChar32) - { - return false; // FIXME: implement! - } - - inline int umemcasecmp(const wchar_t* a, const wchar_t* b, int len) - { - for (int i = 0; i < len; ++i) { - wchar_t c1 = foldCase(a[i]); - wchar_t c2 = foldCase(b[i]); - if (c1 != c2) - return c1 - c2; - } - return 0; - } - - inline UChar32 surrogateToUcs4(wchar_t high, wchar_t low) - { - return (UChar32(high) << 10) + low - 0x35fdc00; - } - - } // namespace Unicode - -} // namespace WTF - -#endif -// vim: ts=2 sw=2 et diff --git a/JavaScriptCore/wtf/url/api/ParsedURL.cpp b/JavaScriptCore/wtf/url/api/ParsedURL.cpp new file mode 100644 index 0000000..abe0061 --- /dev/null +++ b/JavaScriptCore/wtf/url/api/ParsedURL.cpp @@ -0,0 +1,90 @@ +/* + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ParsedURL.h" + +#include "URLComponent.h" +#include "URLParser.h" + +namespace WTF { + +ParsedURL::ParsedURL(const URLString& spec) + : m_spec(spec) +{ + // FIXME: Handle non-standard URLs. + if (spec.string().isEmpty()) + return; + URLParser<UChar>::parseStandardURL(spec.string().characters(), spec.string().length(), m_segments); +} + +String ParsedURL::scheme() const +{ + return segment(m_segments.scheme); +} + +String ParsedURL::username() const +{ + return segment(m_segments.username); +} + +String ParsedURL::password() const +{ + return segment(m_segments.password); +} + +String ParsedURL::host() const +{ + return segment(m_segments.host); +} + +String ParsedURL::port() const +{ + return segment(m_segments.port); +} + +String ParsedURL::path() const +{ + return segment(m_segments.path); +} + +String ParsedURL::query() const +{ + return segment(m_segments.query); +} + +String ParsedURL::fragment() const +{ + return segment(m_segments.fragment); +} + +String ParsedURL::segment(const URLComponent& component) const +{ + if (!component.isValid()) + return String(); + return m_spec.string().substring(component.begin(), component.length()); +} + +} diff --git a/JavaScriptCore/wtf/url/api/ParsedURL.h b/JavaScriptCore/wtf/url/api/ParsedURL.h new file mode 100644 index 0000000..ebc19b7 --- /dev/null +++ b/JavaScriptCore/wtf/url/api/ParsedURL.h @@ -0,0 +1,62 @@ +/* + * 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: + * 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 ParsedURL_h +#define ParsedURL_h + +#include "URLSegments.h" +#include "URLString.h" + +namespace WTF { + +class URLComponent; + +class ParsedURL { +public: + explicit ParsedURL(const URLString&); + + // FIXME: Add a method for parsing non-canonicalized URLs. + + String scheme() const; + String username() const; + String password() const; + String host() const; + String port() const; + String path() const; + String query() const; + String fragment() const; + + URLString spec() { return m_spec; } + +private: + inline String segment(const URLComponent&) const; + + URLString m_spec; + URLSegments m_segments; +}; + +} + +#endif diff --git a/JavaScriptCore/wtf/url/api/URLString.h b/JavaScriptCore/wtf/url/api/URLString.h new file mode 100644 index 0000000..7395d49 --- /dev/null +++ b/JavaScriptCore/wtf/url/api/URLString.h @@ -0,0 +1,55 @@ +/* + * 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: + * 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 URLString_h +#define URLString_h + +#include "WTFString.h" + +namespace WTF { + +// URLString represents a string that's a canonicalized URL. +class URLString { +public: + URLString() { } + + const String& string() const { return m_string;} + +private: + friend class ParsedURL; + + // URLString can only be constructed by a ParsedURL. + explicit URLString(const String& string) + : m_string(string) + { + } + + String m_string; +}; + +} + +#endif + diff --git a/JavaScriptCore/wtf/url/src/RawURLBuffer.h b/JavaScriptCore/wtf/url/src/RawURLBuffer.h new file mode 100644 index 0000000..9bb2e8e --- /dev/null +++ b/JavaScriptCore/wtf/url/src/RawURLBuffer.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 RawURLBuffer_h +#define RawURLBuffer_h + +#include "URLBuffer.h" +#include <stdlib.h> + +namespace WTF { + +// Simple implementation of the URLBuffer using new[]. This class +// also supports a static buffer so if it is allocated on the stack, most +// URLs can be canonicalized with no heap allocations. +template<typename CHAR, int inlineCapacity = 1024> +class RawURLBuffer : public URLBuffer<CHAR> { +public: + RawURLBuffer() : URLBuffer<CHAR>() + { + this->m_buffer = m_inlineBuffer; + this->m_capacity = inlineCapacity; + } + + virtual ~RawURLBuffer() + { + if (this->m_buffer != m_inlineBuffer) + delete[] this->m_buffer; + } + + virtual void resize(int size) + { + CHAR* newBuffer = new CHAR[size]; + memcpy(newBuffer, this->m_buffer, sizeof(CHAR) * (this->m_length < size ? this->m_length : size)); + if (this->m_buffer != m_inlineBuffer) + delete[] this->m_buffer; + this->m_buffer = newBuffer; + this->m_capacity = size; + } + +protected: + CHAR m_inlineBuffer[inlineCapacity]; +}; + +} // namespace WTF + +#endif // RawURLBuffer_h diff --git a/JavaScriptCore/wtf/url/src/URLBuffer.h b/JavaScriptCore/wtf/url/src/URLBuffer.h new file mode 100644 index 0000000..e07402e --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLBuffer.h @@ -0,0 +1,136 @@ +// 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 URLBuffer_h +#define URLBuffer_h + +namespace WTF { + +// Base class for the canonicalizer output, this maintains a buffer and +// supports simple resizing and append operations on it. +// +// It is VERY IMPORTANT that no virtual function calls be made on the common +// code path. We only have two virtual function calls, the destructor and a +// resize function that is called when the existing buffer is not big enough. +// The derived class is then in charge of setting up our buffer which we will +// manage. +template<typename CHAR> +class URLBuffer { +public: + URLBuffer() : m_buffer(0), m_capacity(0), m_length(0) { } + virtual ~URLBuffer() { } + + // Implemented to resize the buffer. This function should update the buffer + // pointer to point to the new buffer, and any old data up to |m_length| in + // the buffer must be copied over. + // + // The new size must be larger than m_capacity. + virtual void resize(int) = 0; + + inline char at(int offset) const { return m_buffer[offset]; } + inline void set(int offset, CHAR ch) + { + // FIXME: Add ASSERT(offset < length()); + m_buffer[offset] = ch; + } + + // Returns the current capacity of the buffer. The length() is the number of + // characters that have been declared to be written, but the capacity() is + // the number that can be written without reallocation. If the caller must + // write many characters at once, it can make sure there is enough capacity, + // write the data, then use setLength() to declare the new length(). + int capacity() const { return m_capacity; } + int length() const { return m_length; } + + // The output will NOT be 0-terminated. Call length() to get the length. + const CHAR* data() const { return m_buffer; } + CHAR* data() { return m_buffer; } + + // Shortens the URL to the new length. Used for "backing up" when processing + // relative paths. This can also be used if an external function writes a lot + // of data to the buffer (when using the "Raw" version below) beyond the end, + // to declare the new length. + void setLength(int length) + { + // FIXME: Add ASSERT(length < capacity()); + m_length = length; + } + + // This is the most performance critical function, since it is called for + // every character. + void append(CHAR ch) + { + // In VC2005, putting this common case first speeds up execution + // dramatically because this branch is predicted as taken. + if (m_length < m_capacity) { + m_buffer[m_length] = ch; + ++m_length; + return; + } + + if (!grow(1)) + return; + + m_buffer[m_length] = ch; + ++m_length; + } + + void append(const CHAR* str, int strLength) + { + if (m_length + strLength > m_capacity) { + if (!grow(m_length + strLength - m_capacity)) + return; + } + for (int i = 0; i < strLength; i++) + m_buffer[m_length + i] = str[i]; + m_length += strLength; + } + +protected: + // Returns true if the buffer could be resized, false on OOM. + bool grow(int minimumAdditionalCapacity) + { + static const int minimumCapacity = 16; + int newCapacity = m_capacity ? m_capacity : minimumCapacity; + do { + if (newCapacity >= (1 << 30)) // Prevent overflow below. + return false; + newCapacity *= 2; + } while (newCapacity < m_capacity + minimumAdditionalCapacity); + resize(newCapacity); + return true; + } + + CHAR* m_buffer; + int m_capacity; + int m_length; // Used characters in the buffer. +}; + +} // namespace WTF + +#endif // URLBuffer_h diff --git a/JavaScriptCore/wtf/url/src/URLCharacterTypes.cpp b/JavaScriptCore/wtf/url/src/URLCharacterTypes.cpp new file mode 100644 index 0000000..ee2014e --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLCharacterTypes.cpp @@ -0,0 +1,173 @@ +// 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. + +#include "config.h" +#include "URLCharacterTypes.h" + +namespace WTF { + +const unsigned char URLCharacterTypes::characterTypeTable[0x100] = { + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x00 - 0x0f + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x10 - 0x1f + InvalidCharacter, // 0x20 ' ' (escape spaces in queries) + QueryCharacter | UserInfoCharacter, // 0x21 ! + InvalidCharacter, // 0x22 " + InvalidCharacter, // 0x23 # (invalid in query since it marks the ref) + QueryCharacter | UserInfoCharacter, // 0x24 $ + QueryCharacter | UserInfoCharacter, // 0x25 % + QueryCharacter | UserInfoCharacter, // 0x26 & + QueryCharacter | UserInfoCharacter, // 0x27 ' + QueryCharacter | UserInfoCharacter, // 0x28 ( + QueryCharacter | UserInfoCharacter, // 0x29 ) + QueryCharacter | UserInfoCharacter, // 0x2a * + QueryCharacter | UserInfoCharacter, // 0x2b + + QueryCharacter | UserInfoCharacter, // 0x2c , + QueryCharacter | UserInfoCharacter, // 0x2d - + QueryCharacter | UserInfoCharacter | IPv4Character, // 0x2e . + QueryCharacter, // 0x2f / + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x30 0 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x31 1 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x32 2 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x33 3 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x34 4 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x35 5 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x36 6 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x37 7 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter, // 0x38 8 + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter, // 0x39 9 + QueryCharacter, // 0x3a : + QueryCharacter, // 0x3b ; + InvalidCharacter, // 0x3c < + QueryCharacter, // 0x3d = + InvalidCharacter, // 0x3e > + QueryCharacter, // 0x3f ? + QueryCharacter, // 0x40 @ + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x41 A + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x42 B + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x43 C + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x44 D + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x45 E + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x46 F + QueryCharacter | UserInfoCharacter, // 0x47 G + QueryCharacter | UserInfoCharacter, // 0x48 H + QueryCharacter | UserInfoCharacter, // 0x49 I + QueryCharacter | UserInfoCharacter, // 0x4a J + QueryCharacter | UserInfoCharacter, // 0x4b K + QueryCharacter | UserInfoCharacter, // 0x4c L + QueryCharacter | UserInfoCharacter, // 0x4d M + QueryCharacter | UserInfoCharacter, // 0x4e N + QueryCharacter | UserInfoCharacter, // 0x4f O + QueryCharacter | UserInfoCharacter, // 0x50 P + QueryCharacter | UserInfoCharacter, // 0x51 Q + QueryCharacter | UserInfoCharacter, // 0x52 R + QueryCharacter | UserInfoCharacter, // 0x53 S + QueryCharacter | UserInfoCharacter, // 0x54 T + QueryCharacter | UserInfoCharacter, // 0x55 U + QueryCharacter | UserInfoCharacter, // 0x56 V + QueryCharacter | UserInfoCharacter, // 0x57 W + QueryCharacter | UserInfoCharacter | IPv4Character, // 0x58 X + QueryCharacter | UserInfoCharacter, // 0x59 Y + QueryCharacter | UserInfoCharacter, // 0x5a Z + QueryCharacter, // 0x5b [ + QueryCharacter, // 0x5c '\' + QueryCharacter, // 0x5d ] + QueryCharacter, // 0x5e ^ + QueryCharacter | UserInfoCharacter, // 0x5f _ + QueryCharacter, // 0x60 ` + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x61 a + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x62 b + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x63 c + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x64 d + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x65 e + QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x66 f + QueryCharacter | UserInfoCharacter, // 0x67 g + QueryCharacter | UserInfoCharacter, // 0x68 h + QueryCharacter | UserInfoCharacter, // 0x69 i + QueryCharacter | UserInfoCharacter, // 0x6a j + QueryCharacter | UserInfoCharacter, // 0x6b k + QueryCharacter | UserInfoCharacter, // 0x6c l + QueryCharacter | UserInfoCharacter, // 0x6d m + QueryCharacter | UserInfoCharacter, // 0x6e n + QueryCharacter | UserInfoCharacter, // 0x6f o + QueryCharacter | UserInfoCharacter, // 0x70 p + QueryCharacter | UserInfoCharacter, // 0x71 q + QueryCharacter | UserInfoCharacter, // 0x72 r + QueryCharacter | UserInfoCharacter, // 0x73 s + QueryCharacter | UserInfoCharacter, // 0x74 t + QueryCharacter | UserInfoCharacter, // 0x75 u + QueryCharacter | UserInfoCharacter, // 0x76 v + QueryCharacter | UserInfoCharacter, // 0x77 w + QueryCharacter | UserInfoCharacter | IPv4Character, // 0x78 x + QueryCharacter | UserInfoCharacter, // 0x79 y + QueryCharacter | UserInfoCharacter, // 0x7a z + QueryCharacter, // 0x7b { + QueryCharacter, // 0x7c | + QueryCharacter, // 0x7d } + QueryCharacter | UserInfoCharacter, // 0x7e ~ + InvalidCharacter, // 0x7f + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x80 - 0x8f + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x90 - 0x9f + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xa0 - 0xaf + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xb0 - 0xbf + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xc0 - 0xcf + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xd0 - 0xdf + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xe0 - 0xef + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, + InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xf0 - 0xff +}; + +} diff --git a/JavaScriptCore/wtf/url/src/URLCharacterTypes.h b/JavaScriptCore/wtf/url/src/URLCharacterTypes.h new file mode 100644 index 0000000..194f6b0 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLCharacterTypes.h @@ -0,0 +1,61 @@ +// 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 URLCharacterTypes_h +#define URLCharacterTypes_h + +namespace WTF { + +class URLCharacterTypes { +public: + static inline bool isQueryChar(unsigned char c) { return isCharOfType(c, QueryCharacter); } + static inline bool isIPv4Char(unsigned char c) { return isCharOfType(c, IPv4Character); } + static inline bool isHexChar(unsigned char c) { return isCharOfType(c, HexCharacter); } + +private: + enum CharTypes { + InvalidCharacter = 0, + QueryCharacter = 1 << 0, + UserInfoCharacter = 1 << 1, + IPv4Character = 1 << 2, + HexCharacter = 1 << 3, + DecimalCharacter = 1 << 4, + OctalCharacter = 1 << 5, + }; + + static const unsigned char characterTypeTable[0x100]; + + static inline bool isCharOfType(unsigned char c, CharTypes type) + { + return !!(characterTypeTable[c] & type); + } +}; + +} + +#endif diff --git a/JavaScriptCore/wtf/url/src/URLComponent.h b/JavaScriptCore/wtf/url/src/URLComponent.h new file mode 100644 index 0000000..1b7976e --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLComponent.h @@ -0,0 +1,77 @@ +// 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) { } + + // Helper that returns a component created with the given begin and ending + // points. The ending point is non-inclusive. + static inline URLComponent fromRange(int begin, int end) + { + return URLComponent(begin, end - begin); + } + + // 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; } + + bool isNonEmpty() const { return m_length > 0; } + bool isEmptyOrInvalid() 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/URLEscape.cpp b/JavaScriptCore/wtf/url/src/URLEscape.cpp new file mode 100644 index 0000000..2987343 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLEscape.cpp @@ -0,0 +1,39 @@ +// 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. + +#include "config.h" +#include "URLEscape.h" + +namespace WTF { + +const char hexCharacterTable[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', +}; + +} diff --git a/JavaScriptCore/wtf/url/src/URLEscape.h b/JavaScriptCore/wtf/url/src/URLEscape.h new file mode 100644 index 0000000..cc2b77f --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLEscape.h @@ -0,0 +1,49 @@ +// 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 URLEscape_h +#define URLEscape_h + +#include "URLBuffer.h" + +namespace WTF { + +extern const char hexCharacterTable[16]; + +template<typename InChar, typename OutChar> +inline void appendURLEscapedCharacter(InChar ch, URLBuffer<OutChar>& buffer) +{ + buffer.append('%'); + buffer.append(hexCharacterTable[ch >> 4]); + buffer.append(hexCharacterTable[ch & 0xf]); +} + +} + +#endif diff --git a/JavaScriptCore/wtf/url/src/URLParser.h b/JavaScriptCore/wtf/url/src/URLParser.h new file mode 100644 index 0000000..4d5ca51 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLParser.h @@ -0,0 +1,575 @@ +/* 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. + */ + +#ifndef URLParser_h +#define URLParser_h + +#include "URLComponent.h" +#include "URLSegments.h" + +namespace WTF { + +template<typename CHAR> +class URLParser { +public: + enum SpecialPort { + UnspecifiedPort = -1, + InvalidPort = -2, + }; + + // This handles everything that may be an authority terminator, including + // backslash. For special backslash handling see parseAfterScheme. + static bool isPossibleAuthorityTerminator(CHAR ch) + { + return isURLSlash(ch) || ch == '?' || ch == '#' || ch == ';'; + } + + // Given an already-identified auth section, breaks it into its constituent + // parts. The port number will be parsed and the resulting integer will be + // filled into the given *port variable, or -1 if there is no port number + // or it is invalid. + static void parseAuthority(const CHAR* spec, const URLComponent& auth, URLComponent& username, URLComponent& password, URLComponent& host, URLComponent& port) + { + // FIXME: add ASSERT(auth.isValid()); // We should always get an authority. + if (!auth.length()) { + username.reset(); + password.reset(); + host.reset(); + port.reset(); + return; + } + + // Search backwards for @, which is the separator between the user info + // and the server info. RFC 3986 forbids @ from occuring in auth, but + // someone might include it in a password unescaped. + int i = auth.begin() + auth.length() - 1; + while (i > auth.begin() && spec[i] != '@') + --i; + + if (spec[i] == '@') { + // Found user info: <user-info>@<server-info> + parseUserInfo(spec, URLComponent(auth.begin(), i - auth.begin()), username, password); + parseServerInfo(spec, URLComponent::fromRange(i + 1, auth.begin() + auth.length()), host, port); + } else { + // No user info, everything is server info. + username.reset(); + password.reset(); + parseServerInfo(spec, auth, host, port); + } + } + + static bool extractScheme(const CHAR* spec, int specLength, URLComponent& scheme) + { + // Skip leading whitespace and control characters. + int begin = 0; + while (begin < specLength && shouldTrimFromURL(spec[begin])) + begin++; + if (begin == specLength) + return false; // Input is empty or all whitespace. + + // Find the first colon character. + for (int i = begin; i < specLength; i++) { + if (spec[i] == ':') { + scheme = URLComponent::fromRange(begin, i); + return true; + } + } + return false; // No colon found: no scheme + } + + // Fills in all members of the URLSegments structure (except for the + // scheme) for standard URLs. + // + // |spec| is the full spec being parsed, of length |specLength|. + // |afterScheme| is the character immediately following the scheme (after + // the colon) where we'll begin parsing. + static void parseAfterScheme(const CHAR* spec, int specLength, int afterScheme, URLSegments& parsed) + { + int numberOfSlashes = consecutiveSlashes(spec, afterScheme, specLength); + int afterSlashes = afterScheme + numberOfSlashes; + + // First split into two main parts, the authority (username, password, + // host, and port) and the full path (path, query, and reference). + URLComponent authority; + URLComponent fullPath; + + // Found "//<some data>", looks like an authority section. Treat + // everything from there to the next slash (or end of spec) to be the + // authority. Note that we ignore the number of slashes and treat it as + // the authority. + int authEnd = nextAuthorityTerminator(spec, afterSlashes, specLength); + authority = URLComponent(afterSlashes, authEnd - afterSlashes); + + if (authEnd == specLength) // No beginning of path found. + fullPath = URLComponent(); + else // Everything starting from the slash to the end is the path. + fullPath = URLComponent(authEnd, specLength - authEnd); + + // Now parse those two sub-parts. + parseAuthority(spec, authority, parsed.username, parsed.password, parsed.host, parsed.port); + parsePath(spec, fullPath, parsed.path, parsed.query, parsed.fragment); + } + + // The main parsing function for standard URLs. Standard URLs have a scheme, + // host, path, etc. + static void parseStandardURL(const CHAR* spec, int specLength, URLSegments& parsed) + { + // FIXME: add ASSERT(specLength >= 0); + + // Strip leading & trailing spaces and control characters. + int begin = 0; + trimURL(spec, begin, specLength); + + int afterScheme; + if (extractScheme(spec, specLength, parsed.scheme)) + afterScheme = parsed.scheme.end() + 1; // Skip past the colon. + else { + // Say there's no scheme when there is a colon. We could also say + // that everything is the scheme. Both would produce an invalid + // URL, but this way seems less wrong in more cases. + parsed.scheme.reset(); + afterScheme = begin; + } + parseAfterScheme(spec, specLength, afterScheme, parsed); + } + + static void parsePath(const CHAR* spec, const URLComponent& path, URLComponent& filepath, URLComponent& query, URLComponent& fragment) + { + // path = [/]<segment1>/<segment2>/<...>/<segmentN>;<param>?<query>#<fragment> + + // Special case when there is no path. + if (!path.isValid()) { + filepath.reset(); + query.reset(); + fragment.reset(); + return; + } + // FIXME: add ASSERT(path.length() > 0); // We should never have 0 length paths. + + // Search for first occurrence of either ? or #. + int pathEnd = path.begin() + path.length(); + + int querySeparator = -1; // Index of the '?' + int refSeparator = -1; // Index of the '#' + for (int i = path.begin(); i < pathEnd; i++) { + switch (spec[i]) { + case '?': + if (querySeparator < 0) + querySeparator = i; + break; + case '#': + refSeparator = i; + i = pathEnd; // Break out of the loop. + break; + default: + break; + } + } + + // Markers pointing to the character after each of these corresponding + // components. The code below works from the end back to the beginning, + // and will update these indices as it finds components that exist. + int fileEnd, queryEnd; + + // Fragment: from the # to the end of the path. + if (refSeparator >= 0) { + fileEnd = refSeparator; + queryEnd = refSeparator; + fragment = URLComponent::fromRange(refSeparator + 1, pathEnd); + } else { + fileEnd = pathEnd; + queryEnd = pathEnd; + fragment.reset(); + } + + // Query fragment: everything from the ? to the next boundary (either + // the end of the path or the fragment fragment). + if (querySeparator >= 0) { + fileEnd = querySeparator; + query = URLComponent::fromRange(querySeparator + 1, queryEnd); + } else + query.reset(); + + // File path: treat an empty file path as no file path. + if (fileEnd != path.begin()) + filepath = URLComponent::fromRange(path.begin(), fileEnd); + else + filepath.reset(); + } + + // Initializes a path URL which is merely a scheme followed by a path. + // Examples include "about:foo" and "javascript:alert('bar');" + static void parsePathURL(const CHAR* spec, int specLength, URLSegments& parsed) + { + // Get the non-path and non-scheme parts of the URL out of the way, we + // never use them. + parsed.username.reset(); + parsed.password.reset(); + parsed.host.reset(); + parsed.port.reset(); + parsed.query.reset(); + parsed.fragment.reset(); + + // Strip leading & trailing spaces and control characters. + // FIXME: Perhaps this is unnecessary? + int begin = 0; + trimURL(spec, begin, specLength); + + // Handle empty specs or ones that contain only whitespace or control + // chars. + if (begin == specLength) { + parsed.scheme.reset(); + parsed.path.reset(); + return; + } + + // Extract the scheme, with the path being everything following. We also + // handle the case where there is no scheme. + if (extractScheme(&spec[begin], specLength - begin, parsed.scheme)) { + // Offset the results since we gave extractScheme a substring. + parsed.scheme.setBegin(parsed.scheme.begin() + begin); + + // For compatibility with the standard URL parser, we treat no path + // as -1, rather than having a length of 0 (we normally wouldn't + // care so much for these non-standard URLs). + if (parsed.scheme.end() == specLength - 1) + parsed.path.reset(); + else + parsed.path = URLComponent::fromRange(parsed.scheme.end() + 1, specLength); + } else { + // No scheme found, just path. + parsed.scheme.reset(); + parsed.path = URLComponent::fromRange(begin, specLength); + } + } + + static void parseMailtoURL(const CHAR* spec, int specLength, URLSegments& parsed) + { + // FIXME: add ASSERT(specLength >= 0); + + // Get the non-path and non-scheme parts of the URL out of the way, we + // never use them. + parsed.username.reset(); + parsed.password.reset(); + parsed.host.reset(); + parsed.port.reset(); + parsed.fragment.reset(); + parsed.query.reset(); // May use this; reset for convenience. + + // Strip leading & trailing spaces and control characters. + int begin = 0; + trimURL(spec, begin, specLength); + + // Handle empty specs or ones that contain only whitespace or control + // chars. + if (begin == specLength) { + parsed.scheme.reset(); + parsed.path.reset(); + return; + } + + int pathBegin = -1; + int pathEnd = -1; + + // Extract the scheme, with the path being everything following. We also + // handle the case where there is no scheme. + if (extractScheme(&spec[begin], specLength - begin, parsed.scheme)) { + // Offset the results since we gave extractScheme a substring. + parsed.scheme.setBegin(parsed.scheme.begin() + begin); + + if (parsed.scheme.end() != specLength - 1) { + pathBegin = parsed.scheme.end() + 1; + pathEnd = specLength; + } + } else { + // No scheme found, just path. + parsed.scheme.reset(); + pathBegin = begin; + pathEnd = specLength; + } + + // Split [pathBegin, pathEnd) into a path + query. + for (int i = pathBegin; i < pathEnd; ++i) { + if (spec[i] == '?') { + parsed.query = URLComponent::fromRange(i + 1, pathEnd); + pathEnd = i; + break; + } + } + + // For compatibility with the standard URL parser, treat no path as + // -1, rather than having a length of 0 + if (pathBegin == pathEnd) + parsed.path.reset(); + else + parsed.path = URLComponent::fromRange(pathBegin, pathEnd); + } + + static int parsePort(const CHAR* spec, const URLComponent& component) + { + // Easy success case when there is no port. + const int maxDigits = 5; + if (component.isEmptyOrInvalid()) + return UnspecifiedPort; + + URLComponent nonZeroDigits(component.end(), 0); + for (int i = 0; i < component.length(); ++i) { + if (spec[component.begin() + i] != '0') { + nonZeroDigits = URLComponent::fromRange(component.begin() + i, component.end()); + break; + } + } + if (!nonZeroDigits.length()) + return 0; // All digits were 0. + + if (nonZeroDigits.length() > maxDigits) + return InvalidPort; + + int port = 0; + for (int i = 0; i < nonZeroDigits.length(); ++i) { + CHAR ch = spec[nonZeroDigits.begin() + i]; + if (!isPortDigit(ch)) + return InvalidPort; + port *= 10; + port += static_cast<char>(ch) - '0'; + } + if (port > 65535) + return InvalidPort; + return port; + } + + static void extractFileName(const CHAR* spec, const URLComponent& path, URLComponent& fileName) + { + // Handle empty paths: they have no file names. + if (path.isEmptyOrInvalid()) { + fileName.reset(); + return; + } + + // Search backwards for a parameter, which is a normally unused field + // in a URL delimited by a semicolon. We parse the parameter as part of + // the path, but here, we don't want to count it. The last semicolon is + // the parameter. + int fileEnd = path.end(); + for (int i = path.end() - 1; i > path.begin(); --i) { + if (spec[i] == ';') { + fileEnd = i; + break; + } + } + + // Now search backwards from the filename end to the previous slash + // to find the beginning of the filename. + for (int i = fileEnd - 1; i >= path.begin(); --i) { + if (isURLSlash(spec[i])) { + // File name is everything following this character to the end + fileName = URLComponent::fromRange(i + 1, fileEnd); + return; + } + } + + // No slash found, this means the input was degenerate (generally paths + // will start with a slash). Let's call everything the file name. + fileName = URLComponent::fromRange(path.begin(), fileEnd); + } + + static bool extractQueryKeyValue(const CHAR* spec, URLComponent& query, URLComponent& key, URLComponent& value) + { + if (query.isEmptyOrInvalid()) + return false; + + int start = query.begin(); + int current = start; + int end = query.end(); + + // We assume the beginning of the input is the beginning of the "key" + // and we skip to the end of it. + key.setBegin(current); + while (current < end && spec[current] != '&' && spec[current] != '=') + ++current; + key.setLength(current - key.begin()); + + // Skip the separator after the key (if any). + if (current < end && spec[current] == '=') + ++current; + + // Find the value part. + value.setBegin(current); + while (current < end && spec[current] != '&') + ++current; + value.setLength(current - value.begin()); + + // Finally skip the next separator if any + if (current < end && spec[current] == '&') + ++current; + + // Save the new query + query = URLComponent::fromRange(current, end); + return true; + } + +// FIXME: This should be protected or private. +public: + // We treat slashes and backslashes the same for IE compatibility. + static inline bool isURLSlash(CHAR ch) + { + return ch == '/' || ch == '\\'; + } + + // Returns true if we should trim this character from the URL because it is + // a space or a control character. + static inline bool shouldTrimFromURL(CHAR ch) + { + return ch <= ' '; + } + + // Given an already-initialized begin index and end index (the index after + // the last CHAR in spec), this shrinks the range to eliminate + // "should-be-trimmed" characters. + static inline void trimURL(const CHAR* spec, int& begin, int& end) + { + // Strip leading whitespace and control characters. + while (begin < end && shouldTrimFromURL(spec[begin])) + ++begin; + + // Strip trailing whitespace and control characters. We need the >i + // test for when the input string is all blanks; we don't want to back + // past the input. + while (end > begin && shouldTrimFromURL(spec[end - 1])) + --end; + } + + // Counts the number of consecutive slashes starting at the given offset + // in the given string of the given length. + static inline int consecutiveSlashes(const CHAR *string, int beginOffset, int stringLength) + { + int count = 0; + while (beginOffset + count < stringLength && isURLSlash(string[beginOffset + count])) + ++count; + return count; + } + +private: + // URLParser cannot be constructed. + URLParser(); + + // Returns true if the given character is a valid digit to use in a port. + static inline bool isPortDigit(CHAR ch) + { + return ch >= '0' && ch <= '9'; + } + + // Returns the offset of the next authority terminator in the input starting + // from startOffset. If no terminator is found, the return value will be equal + // to specLength. + static int nextAuthorityTerminator(const CHAR* spec, int startOffset, int specLength) + { + for (int i = startOffset; i < specLength; i++) { + if (isPossibleAuthorityTerminator(spec[i])) + return i; + } + return specLength; // Not found. + } + + static void parseUserInfo(const CHAR* spec, const URLComponent& user, URLComponent& username, URLComponent& password) + { + // Find the first colon in the user section, which separates the + // username and password. + int colonOffset = 0; + while (colonOffset < user.length() && spec[user.begin() + colonOffset] != ':') + ++colonOffset; + + if (colonOffset < user.length()) { + // Found separator: <username>:<password> + username = URLComponent(user.begin(), colonOffset); + password = URLComponent::fromRange(user.begin() + colonOffset + 1, user.begin() + user.length()); + } else { + // No separator, treat everything as the username + username = user; + password = URLComponent(); + } + } + + static void parseServerInfo(const CHAR* spec, const URLComponent& serverInfo, URLComponent& host, URLComponent& port) + { + if (!serverInfo.length()) { + // No server info, host name is empty. + host.reset(); + port.reset(); + return; + } + + // If the host starts with a left-bracket, assume the entire host is an + // IPv6 literal. Otherwise, assume none of the host is an IPv6 literal. + // This assumption will be overridden if we find a right-bracket. + // + // Our IPv6 address canonicalization code requires both brackets to + // exist, but the ability to locate an incomplete address can still be + // useful. + int ipv6Terminator = spec[serverInfo.begin()] == '[' ? serverInfo.end() : -1; + int colon = -1; + + // Find the last right-bracket, and the last colon. + for (int i = serverInfo.begin(); i < serverInfo.end(); i++) { + switch (spec[i]) { + case ']': + ipv6Terminator = i; + break; + case ':': + colon = i; + break; + default: + break; + } + } + + if (colon > ipv6Terminator) { + // Found a port number: <hostname>:<port> + host = URLComponent::fromRange(serverInfo.begin(), colon); + if (!host.length()) + host.reset(); + port = URLComponent::fromRange(colon + 1, serverInfo.end()); + } else { + // No port: <hostname> + host = serverInfo; + port.reset(); + } + } +}; + +} // namespace WTF + +#endif // URLParser_h diff --git a/JavaScriptCore/wtf/url/src/URLQueryCanonicalizer.h b/JavaScriptCore/wtf/url/src/URLQueryCanonicalizer.h new file mode 100644 index 0000000..7740200 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLQueryCanonicalizer.h @@ -0,0 +1,107 @@ +// 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 URLQueryCanonicalizer_h +#define URLQueryCanonicalizer_h + +#include "RawURLBuffer.h" +#include "URLBuffer.h" +#include "URLCharacterTypes.h" +#include "URLComponent.h" +#include "URLEscape.h" + +namespace WTF { + +template<typename InChar, typename OutChar, void convertCharset(const InChar*, int length, URLBuffer<char>&)> +class URLQueryCanonicalizer { +public: + static void canonicalize(const InChar* spec, const URLComponent& query, URLBuffer<OutChar>& buffer, URLComponent& resultQuery) + { + if (query.length() < 0) { + resultQuery = URLComponent(); + return; + } + + buffer->append('?'); + resultQuery.setBegin(buffer->length()); + convertToQueryEncoding(spec, query, buffer); + resultQuery.setLength(buffer->length() - resultQuery.begin()); + } + +private: + static bool isAllASCII(const InChar* spec, const URLComponent& query) + { + int end = query.end(); + for (int i = query.begin(); i < end; ++i) { + if (static_cast<unsigned>(spec[i]) >= 0x80) + return false; + } + return true; + } + +#ifndef NDEBUG + static bool isRaw8Bit(const InChar* source, int length) + { + for (int i = source; i < length; ++i) { + if (source[i] & 0xFF != source[i]) + return false; + } + return true; + } +#endif + + static void appendRaw8BitQueryString(const InChar* source, int length, URLBuffer<OutChar>* buffer) + { + ASSERT(isRaw8Bit(source, length)); + for (int i = 0; i < length; ++i) { + if (!URLCharacterTypes::isQueryChar(source[i])) + appendURLEscapedCharacter(static_cast<unsigned char>(source[i]), buffer); + else + buffer->append(static_cast<char>(source[i])); + } + } + + static void convertToQueryEncoding(const InChar* spec, const URLComponent& query, URLBuffer<OutChar>& buffer) + { + if (isAllASCII(spec, query)) { + appendRaw8BitQueryString(&spec[query.begin()], query.length(), buffer); + return; + } + + RawURLBuffer<char, 1024> convertedQuery; + convertCharset(spec, query, convertedQuery); + appendRaw8BitQueryString(convertedQuery.data(), convertedQuery.length(), buffer); + } +}; + +} + +#endif + + 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/wince/FastMallocWince.h b/JavaScriptCore/wtf/wince/FastMallocWinCE.h index 37174f0..d91a5f2 100644 --- a/JavaScriptCore/wtf/wince/FastMallocWince.h +++ b/JavaScriptCore/wtf/wince/FastMallocWinCE.h @@ -19,8 +19,8 @@ * */ -#ifndef FastMallocWince_h -#define FastMallocWince_h +#ifndef WTF_FastMallocWinCE_h +#define WTF_FastMallocWinCE_h #include <new.h> @@ -172,5 +172,4 @@ namespace WTF { #endif -#endif // FastMallocWince_h - +#endif // WTF_FastMallocWinCE_h diff --git a/JavaScriptCore/wtf/wtf.pri b/JavaScriptCore/wtf/wtf.pri new file mode 100644 index 0000000..1780334 --- /dev/null +++ b/JavaScriptCore/wtf/wtf.pri @@ -0,0 +1,45 @@ +# wtf - qmake build info + +SOURCES += \ + wtf/Assertions.cpp \ + wtf/ByteArray.cpp \ + wtf/CurrentTime.cpp \ + wtf/DateMath.cpp \ + wtf/dtoa.cpp \ + wtf/DecimalNumber.cpp \ + wtf/FastMalloc.cpp \ + wtf/gobject/GOwnPtr.cpp \ + wtf/gobject/GRefPtr.cpp \ + wtf/HashTable.cpp \ + wtf/MD5.cpp \ + wtf/MainThread.cpp \ + wtf/qt/MainThreadQt.cpp \ + wtf/qt/StringQt.cpp \ + wtf/qt/ThreadingQt.cpp \ + wtf/PageAllocation.cpp \ + wtf/RandomNumber.cpp \ + wtf/RefCountedLeakCounter.cpp \ + wtf/ThreadingNone.cpp \ + wtf/Threading.cpp \ + wtf/TypeTraits.cpp \ + wtf/WTFThreadData.cpp \ + wtf/text/AtomicString.cpp \ + wtf/text/CString.cpp \ + wtf/text/StringBuilder.cpp \ + wtf/text/StringImpl.cpp \ + wtf/text/StringStatics.cpp \ + wtf/text/WTFString.cpp \ + wtf/unicode/CollatorDefault.cpp \ + wtf/unicode/icu/CollatorICU.cpp \ + wtf/unicode/UTF8.cpp + +contains(DEFINES, USE_GSTREAMER=1) { + DEFINES += ENABLE_GLIB_SUPPORT=1 + PKGCONFIG += glib-2.0 gio-2.0 + CONFIG += link_pkgconfig +} + +!contains(DEFINES, USE_SYSTEM_MALLOC) { + SOURCES += wtf/TCSystemAlloc.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 |
