summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/wtf
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/wtf')
-rw-r--r--Source/JavaScriptCore/wtf/ASCIICType.h161
-rw-r--r--Source/JavaScriptCore/wtf/AVLTree.h960
-rw-r--r--Source/JavaScriptCore/wtf/Alignment.h63
-rw-r--r--Source/JavaScriptCore/wtf/AlwaysInline.h23
-rw-r--r--Source/JavaScriptCore/wtf/ArrayBuffer.cpp78
-rw-r--r--Source/JavaScriptCore/wtf/ArrayBuffer.h220
-rw-r--r--Source/JavaScriptCore/wtf/ArrayBufferView.cpp55
-rw-r--r--Source/JavaScriptCore/wtf/ArrayBufferView.h198
-rw-r--r--Source/JavaScriptCore/wtf/Assertions.cpp320
-rw-r--r--Source/JavaScriptCore/wtf/Assertions.h392
-rw-r--r--Source/JavaScriptCore/wtf/Atomics.h196
-rw-r--r--Source/JavaScriptCore/wtf/BitVector.cpp120
-rw-r--r--Source/JavaScriptCore/wtf/BitVector.h243
-rw-r--r--Source/JavaScriptCore/wtf/Bitmap.h225
-rw-r--r--Source/JavaScriptCore/wtf/BlockStack.h96
-rw-r--r--Source/JavaScriptCore/wtf/BloomFilter.h139
-rw-r--r--Source/JavaScriptCore/wtf/BoundsCheckedPointer.h287
-rw-r--r--Source/JavaScriptCore/wtf/BumpPointerAllocator.h250
-rw-r--r--Source/JavaScriptCore/wtf/ByteArray.cpp40
-rw-r--r--Source/JavaScriptCore/wtf/ByteArray.h110
-rw-r--r--Source/JavaScriptCore/wtf/CMakeLists.txt226
-rw-r--r--Source/JavaScriptCore/wtf/CONTRIBUTORS.pthreads-win32137
-rw-r--r--Source/JavaScriptCore/wtf/CheckedArithmetic.h693
-rw-r--r--Source/JavaScriptCore/wtf/Compiler.h242
-rw-r--r--Source/JavaScriptCore/wtf/Complex.h49
-rw-r--r--Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp180
-rw-r--r--Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h45
-rw-r--r--Source/JavaScriptCore/wtf/CurrentTime.cpp347
-rw-r--r--Source/JavaScriptCore/wtf/CurrentTime.h72
-rw-r--r--Source/JavaScriptCore/wtf/DateMath.cpp1062
-rw-r--r--Source/JavaScriptCore/wtf/DateMath.h126
-rw-r--r--Source/JavaScriptCore/wtf/DecimalNumber.cpp199
-rw-r--r--Source/JavaScriptCore/wtf/DecimalNumber.h108
-rw-r--r--Source/JavaScriptCore/wtf/Decoder.h57
-rw-r--r--Source/JavaScriptCore/wtf/Deque.h690
-rw-r--r--Source/JavaScriptCore/wtf/DisallowCType.h74
-rw-r--r--Source/JavaScriptCore/wtf/DoublyLinkedList.h168
-rw-r--r--Source/JavaScriptCore/wtf/DynamicAnnotations.cpp61
-rw-r--r--Source/JavaScriptCore/wtf/DynamicAnnotations.h96
-rw-r--r--Source/JavaScriptCore/wtf/Encoder.h57
-rw-r--r--Source/JavaScriptCore/wtf/ExportMacros.h90
-rw-r--r--Source/JavaScriptCore/wtf/FastAllocBase.h427
-rw-r--r--Source/JavaScriptCore/wtf/FastMalloc.cpp4708
-rw-r--r--Source/JavaScriptCore/wtf/FastMalloc.h281
-rw-r--r--Source/JavaScriptCore/wtf/FixedArray.h58
-rw-r--r--Source/JavaScriptCore/wtf/Float32Array.h108
-rw-r--r--Source/JavaScriptCore/wtf/Float64Array.h108
-rw-r--r--Source/JavaScriptCore/wtf/Forward.h88
-rw-r--r--Source/JavaScriptCore/wtf/Functional.h638
-rw-r--r--Source/JavaScriptCore/wtf/GetPtr.h33
-rw-r--r--Source/JavaScriptCore/wtf/HashCountedSet.h228
-rw-r--r--Source/JavaScriptCore/wtf/HashFunctions.h183
-rw-r--r--Source/JavaScriptCore/wtf/HashIterators.h218
-rw-r--r--Source/JavaScriptCore/wtf/HashMap.h491
-rw-r--r--Source/JavaScriptCore/wtf/HashSet.h261
-rw-r--r--Source/JavaScriptCore/wtf/HashTable.cpp69
-rw-r--r--Source/JavaScriptCore/wtf/HashTable.h1244
-rw-r--r--Source/JavaScriptCore/wtf/HashTraits.h167
-rw-r--r--Source/JavaScriptCore/wtf/HexNumber.h107
-rw-r--r--Source/JavaScriptCore/wtf/InlineASM.h71
-rw-r--r--Source/JavaScriptCore/wtf/Int16Array.h93
-rw-r--r--Source/JavaScriptCore/wtf/Int32Array.h92
-rw-r--r--Source/JavaScriptCore/wtf/Int8Array.h94
-rw-r--r--Source/JavaScriptCore/wtf/IntegralTypedArrayBase.h72
-rw-r--r--Source/JavaScriptCore/wtf/ListHashSet.h853
-rw-r--r--Source/JavaScriptCore/wtf/ListRefPtr.h61
-rw-r--r--Source/JavaScriptCore/wtf/Locker.h48
-rw-r--r--Source/JavaScriptCore/wtf/MD5.cpp309
-rw-r--r--Source/JavaScriptCore/wtf/MD5.h61
-rw-r--r--Source/JavaScriptCore/wtf/MainThread.cpp252
-rw-r--r--Source/JavaScriptCore/wtf/MainThread.h85
-rw-r--r--Source/JavaScriptCore/wtf/MallocZoneSupport.h73
-rw-r--r--Source/JavaScriptCore/wtf/MathExtras.h331
-rw-r--r--Source/JavaScriptCore/wtf/MessageQueue.h226
-rw-r--r--Source/JavaScriptCore/wtf/MetaAllocator.cpp420
-rw-r--r--Source/JavaScriptCore/wtf/MetaAllocator.h174
-rw-r--r--Source/JavaScriptCore/wtf/MetaAllocatorHandle.h98
-rw-r--r--Source/JavaScriptCore/wtf/NonCopyingSort.h89
-rw-r--r--Source/JavaScriptCore/wtf/Noncopyable.h42
-rw-r--r--Source/JavaScriptCore/wtf/NotFound.h37
-rw-r--r--Source/JavaScriptCore/wtf/NullPtr.cpp34
-rw-r--r--Source/JavaScriptCore/wtf/NullPtr.h48
-rw-r--r--Source/JavaScriptCore/wtf/OSAllocator.h100
-rw-r--r--Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp153
-rw-r--r--Source/JavaScriptCore/wtf/OSAllocatorWin.cpp80
-rw-r--r--Source/JavaScriptCore/wtf/OSRandomSource.cpp71
-rw-r--r--Source/JavaScriptCore/wtf/OSRandomSource.h41
-rw-r--r--Source/JavaScriptCore/wtf/OwnArrayPtr.h157
-rw-r--r--Source/JavaScriptCore/wtf/OwnFastMallocPtr.h53
-rw-r--r--Source/JavaScriptCore/wtf/OwnPtr.h169
-rw-r--r--Source/JavaScriptCore/wtf/OwnPtrCommon.h74
-rw-r--r--Source/JavaScriptCore/wtf/PackedIntVector.h126
-rw-r--r--Source/JavaScriptCore/wtf/PageAllocation.h120
-rw-r--r--Source/JavaScriptCore/wtf/PageAllocationAligned.cpp87
-rw-r--r--Source/JavaScriptCore/wtf/PageAllocationAligned.h70
-rw-r--r--Source/JavaScriptCore/wtf/PageBlock.cpp70
-rw-r--r--Source/JavaScriptCore/wtf/PageBlock.h87
-rw-r--r--Source/JavaScriptCore/wtf/PageReservation.h149
-rw-r--r--Source/JavaScriptCore/wtf/ParallelJobs.h105
-rw-r--r--Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp181
-rw-r--r--Source/JavaScriptCore/wtf/ParallelJobsGeneric.h103
-rw-r--r--Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h73
-rw-r--r--Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h81
-rw-r--r--Source/JavaScriptCore/wtf/PassOwnArrayPtr.h169
-rw-r--r--Source/JavaScriptCore/wtf/PassOwnPtr.h172
-rw-r--r--Source/JavaScriptCore/wtf/PassRefPtr.h245
-rw-r--r--Source/JavaScriptCore/wtf/PassTraits.h63
-rw-r--r--Source/JavaScriptCore/wtf/Platform.h1163
-rw-r--r--Source/JavaScriptCore/wtf/PlatformBlackBerry.cmake12
-rw-r--r--Source/JavaScriptCore/wtf/PlatformEfl.cmake50
-rw-r--r--Source/JavaScriptCore/wtf/PlatformWinCE.cmake26
-rw-r--r--Source/JavaScriptCore/wtf/PossiblyNull.h59
-rw-r--r--Source/JavaScriptCore/wtf/RandomNumber.cpp76
-rw-r--r--Source/JavaScriptCore/wtf/RandomNumber.h39
-rw-r--r--Source/JavaScriptCore/wtf/RandomNumberSeed.h81
-rw-r--r--Source/JavaScriptCore/wtf/RedBlackTree.h583
-rw-r--r--Source/JavaScriptCore/wtf/RefCounted.h234
-rw-r--r--Source/JavaScriptCore/wtf/RefCountedLeakCounter.cpp92
-rw-r--r--Source/JavaScriptCore/wtf/RefCountedLeakCounter.h52
-rw-r--r--Source/JavaScriptCore/wtf/RefPtr.h232
-rw-r--r--Source/JavaScriptCore/wtf/RefPtrHashMap.h329
-rw-r--r--Source/JavaScriptCore/wtf/RetainPtr.h299
-rw-r--r--Source/JavaScriptCore/wtf/SHA1.cpp219
-rw-r--r--Source/JavaScriptCore/wtf/SHA1.h66
-rw-r--r--Source/JavaScriptCore/wtf/SegmentedVector.h255
-rw-r--r--Source/JavaScriptCore/wtf/SentinelLinkedList.h159
-rw-r--r--Source/JavaScriptCore/wtf/SinglyLinkedList.h72
-rw-r--r--Source/JavaScriptCore/wtf/SizeLimits.cpp65
-rw-r--r--Source/JavaScriptCore/wtf/Spectrum.h105
-rw-r--r--Source/JavaScriptCore/wtf/StackBounds.cpp261
-rw-r--r--Source/JavaScriptCore/wtf/StackBounds.h114
-rw-r--r--Source/JavaScriptCore/wtf/StaticConstructors.h74
-rw-r--r--Source/JavaScriptCore/wtf/StdLibExtras.h290
-rw-r--r--Source/JavaScriptCore/wtf/StringExtras.cpp62
-rw-r--r--Source/JavaScriptCore/wtf/StringExtras.h126
-rw-r--r--Source/JavaScriptCore/wtf/StringHasher.h185
-rw-r--r--Source/JavaScriptCore/wtf/TCPackedCache.h234
-rw-r--r--Source/JavaScriptCore/wtf/TCPageMap.h316
-rw-r--r--Source/JavaScriptCore/wtf/TCSpinLock.h284
-rw-r--r--Source/JavaScriptCore/wtf/TCSystemAlloc.cpp530
-rw-r--r--Source/JavaScriptCore/wtf/TCSystemAlloc.h75
-rw-r--r--Source/JavaScriptCore/wtf/TemporaryChange.h68
-rw-r--r--Source/JavaScriptCore/wtf/ThreadFunctionInvocation.h49
-rw-r--r--Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp94
-rw-r--r--Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h78
-rw-r--r--Source/JavaScriptCore/wtf/ThreadRestrictionVerifier.h178
-rw-r--r--Source/JavaScriptCore/wtf/ThreadSafeRefCounted.h150
-rw-r--r--Source/JavaScriptCore/wtf/ThreadSpecific.h276
-rw-r--r--Source/JavaScriptCore/wtf/ThreadSpecificWin.cpp53
-rw-r--r--Source/JavaScriptCore/wtf/Threading.cpp100
-rw-r--r--Source/JavaScriptCore/wtf/Threading.h117
-rw-r--r--Source/JavaScriptCore/wtf/ThreadingNone.cpp0
-rw-r--r--Source/JavaScriptCore/wtf/ThreadingPrimitives.h151
-rw-r--r--Source/JavaScriptCore/wtf/ThreadingPthreads.cpp410
-rw-r--r--Source/JavaScriptCore/wtf/ThreadingWin.cpp515
-rw-r--r--Source/JavaScriptCore/wtf/TypeTraits.cpp142
-rw-r--r--Source/JavaScriptCore/wtf/TypeTraits.h389
-rw-r--r--Source/JavaScriptCore/wtf/TypedArrayBase.h130
-rw-r--r--Source/JavaScriptCore/wtf/Uint16Array.h94
-rw-r--r--Source/JavaScriptCore/wtf/Uint32Array.h94
-rw-r--r--Source/JavaScriptCore/wtf/Uint8Array.h94
-rw-r--r--Source/JavaScriptCore/wtf/UnionFind.h105
-rw-r--r--Source/JavaScriptCore/wtf/UnusedParam.h37
-rw-r--r--Source/JavaScriptCore/wtf/VMTags.h75
-rw-r--r--Source/JavaScriptCore/wtf/ValueCheck.h53
-rw-r--r--Source/JavaScriptCore/wtf/Vector.h1191
-rw-r--r--Source/JavaScriptCore/wtf/VectorTraits.h99
-rw-r--r--Source/JavaScriptCore/wtf/WTFThreadData.cpp54
-rw-r--r--Source/JavaScriptCore/wtf/WTFThreadData.h146
-rw-r--r--Source/JavaScriptCore/wtf/blackberry/MainThreadBlackBerry.cpp35
-rw-r--r--Source/JavaScriptCore/wtf/chromium/ChromiumThreading.h44
-rw-r--r--Source/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp73
-rw-r--r--Source/JavaScriptCore/wtf/dtoa.cpp1867
-rw-r--r--Source/JavaScriptCore/wtf/dtoa.h58
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/COPYING26
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/LICENSE26
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/README11
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.cc659
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.h86
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/bignum.cc770
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/bignum.h145
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/cached-powers.cc193
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/cached-powers.h72
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/diy-fp.cc62
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/diy-fp.h122
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/double-conversion.cc870
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/double-conversion.h502
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/double.h249
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/fast-dtoa.cc741
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/fast-dtoa.h88
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.cc410
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.h60
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/strtod.cc447
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/strtod.h45
-rw-r--r--Source/JavaScriptCore/wtf/dtoa/utils.h310
-rw-r--r--Source/JavaScriptCore/wtf/efl/MainThreadEfl.cpp65
-rw-r--r--Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp53
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp54
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GOwnPtr.h141
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GRefPtr.cpp86
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GRefPtr.h229
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GTypedefs.h95
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GlibUtilities.cpp44
-rw-r--r--Source/JavaScriptCore/wtf/gobject/GlibUtilities.h28
-rw-r--r--Source/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp52
-rw-r--r--Source/JavaScriptCore/wtf/mac/MainThreadMac.mm175
-rw-r--r--Source/JavaScriptCore/wtf/qt/MainThreadQt.cpp78
-rw-r--r--Source/JavaScriptCore/wtf/qt/StringQt.cpp73
-rw-r--r--Source/JavaScriptCore/wtf/qt/UtilsQt.h37
-rw-r--r--Source/JavaScriptCore/wtf/qt/compat/QGuiApplication1
-rw-r--r--Source/JavaScriptCore/wtf/qt/compat/qguiapplication.h35
-rw-r--r--Source/JavaScriptCore/wtf/text/ASCIIFastPath.h101
-rw-r--r--Source/JavaScriptCore/wtf/text/AtomicString.cpp320
-rw-r--r--Source/JavaScriptCore/wtf/text/AtomicString.h215
-rw-r--r--Source/JavaScriptCore/wtf/text/AtomicStringHash.h62
-rw-r--r--Source/JavaScriptCore/wtf/text/AtomicStringImpl.h38
-rw-r--r--Source/JavaScriptCore/wtf/text/CString.cpp104
-rw-r--r--Source/JavaScriptCore/wtf/text/CString.h87
-rw-r--r--Source/JavaScriptCore/wtf/text/StringBuffer.h87
-rw-r--r--Source/JavaScriptCore/wtf/text/StringBuilder.cpp301
-rw-r--r--Source/JavaScriptCore/wtf/text/StringBuilder.h234
-rw-r--r--Source/JavaScriptCore/wtf/text/StringConcatenate.h964
-rw-r--r--Source/JavaScriptCore/wtf/text/StringHash.h184
-rw-r--r--Source/JavaScriptCore/wtf/text/StringImpl.cpp1541
-rw-r--r--Source/JavaScriptCore/wtf/text/StringImpl.h774
-rw-r--r--Source/JavaScriptCore/wtf/text/StringOperators.h150
-rw-r--r--Source/JavaScriptCore/wtf/text/StringStatics.cpp92
-rw-r--r--Source/JavaScriptCore/wtf/text/TextPosition.h85
-rw-r--r--Source/JavaScriptCore/wtf/text/WTFString.cpp1126
-rw-r--r--Source/JavaScriptCore/wtf/text/WTFString.h648
-rw-r--r--Source/JavaScriptCore/wtf/threads/BinarySemaphore.cpp68
-rw-r--r--Source/JavaScriptCore/wtf/threads/BinarySemaphore.h63
-rw-r--r--Source/JavaScriptCore/wtf/threads/win/BinarySemaphoreWin.cpp74
-rw-r--r--Source/JavaScriptCore/wtf/unicode/CharacterNames.h144
-rw-r--r--Source/JavaScriptCore/wtf/unicode/Collator.h69
-rw-r--r--Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp75
-rw-r--r--Source/JavaScriptCore/wtf/unicode/ScriptCodesFromICU.h153
-rw-r--r--Source/JavaScriptCore/wtf/unicode/UTF8.cpp449
-rw-r--r--Source/JavaScriptCore/wtf/unicode/UTF8.h84
-rw-r--r--Source/JavaScriptCore/wtf/unicode/Unicode.h45
-rw-r--r--Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h100
-rw-r--r--Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp192
-rw-r--r--Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h244
-rw-r--r--Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp149
-rw-r--r--Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h236
-rw-r--r--Source/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h377
-rw-r--r--Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.cpp181
-rw-r--r--Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h178
-rw-r--r--Source/JavaScriptCore/wtf/win/MainThreadWin.cpp90
-rw-r--r--Source/JavaScriptCore/wtf/win/OwnPtrWin.cpp76
-rw-r--r--Source/JavaScriptCore/wtf/wince/FastMallocWinCE.h175
-rw-r--r--Source/JavaScriptCore/wtf/wince/MemoryManager.cpp171
-rw-r--r--Source/JavaScriptCore/wtf/wince/MemoryManager.h80
-rw-r--r--Source/JavaScriptCore/wtf/wtf.pri44
-rw-r--r--Source/JavaScriptCore/wtf/wtf.pro253
-rw-r--r--Source/JavaScriptCore/wtf/wx/MainThreadWx.cpp66
-rw-r--r--Source/JavaScriptCore/wtf/wx/StringWx.cpp84
257 files changed, 56845 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wtf/ASCIICType.h b/Source/JavaScriptCore/wtf/ASCIICType.h
new file mode 100644
index 000000000..17006ae2d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ASCIICType.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2011 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 WTF_ASCIICType_h
+#define WTF_ASCIICType_h
+
+#include <wtf/Assertions.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
+// are in code processing something that's not locale-specific. These equivalents
+// for some of the <ctype.h> functions are named more explicitly, not dependent
+// on the C library locale, and we should also optimize them as needed.
+
+// All functions return false or leave the character unchanged if passed a character
+// that is outside the range 0-7F. So they can be used on Unicode strings or
+// characters if the intent is to do processing only if the character is ASCII.
+
+namespace WTF {
+
+template<typename CharType> inline bool isASCII(CharType c)
+{
+ return !(c & ~0x7F);
+}
+
+template<typename CharType> inline bool isASCIIAlpha(CharType c)
+{
+ return (c | 0x20) >= 'a' && (c | 0x20) <= 'z';
+}
+
+template<typename CharType> inline bool isASCIIDigit(CharType c)
+{
+ return c >= '0' && c <= '9';
+}
+
+template<typename CharType> inline bool isASCIIAlphanumeric(CharType c)
+{
+ return isASCIIDigit(c) || isASCIIAlpha(c);
+}
+
+template<typename CharType> inline bool isASCIIHexDigit(CharType c)
+{
+ return isASCIIDigit(c) || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
+}
+
+template<typename CharType> inline bool isASCIILower(CharType c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+template<typename CharType> inline bool isASCIIOctalDigit(CharType c)
+{
+ return (c >= '0') & (c <= '7');
+}
+
+template<typename CharType> inline bool isASCIIPrintable(CharType c)
+{
+ return c >= ' ' && c <= '~';
+}
+
+/*
+ Statistics from a run of Apple's page load test for callers of isASCIISpace:
+
+ character count
+ --------- -----
+ non-spaces 689383
+ 20 space 294720
+ 0A \n 89059
+ 09 \t 28320
+ 0D \r 0
+ 0C \f 0
+ 0B \v 0
+ */
+template<typename CharType> inline bool isASCIISpace(CharType c)
+{
+ return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
+}
+
+template<typename CharType> inline bool isASCIIUpper(CharType c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+template<typename CharType> inline CharType toASCIILower(CharType c)
+{
+ return c | ((c >= 'A' && c <= 'Z') << 5);
+}
+
+template<typename CharType> inline CharType toASCIIUpper(CharType c)
+{
+ return c & ~((c >= 'a' && c <= 'z') << 5);
+}
+
+template<typename CharType> inline int toASCIIHexValue(CharType c)
+{
+ ASSERT(isASCIIHexDigit(c));
+ return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF;
+}
+
+template<typename CharType> inline int toASCIIHexValue(CharType upperValue, CharType lowerValue)
+{
+ ASSERT(isASCIIHexDigit(upperValue) && isASCIIHexDigit(lowerValue));
+ return ((toASCIIHexValue(upperValue) << 4) & 0xF0) | toASCIIHexValue(lowerValue);
+}
+
+inline char lowerNibbleToASCIIHexDigit(char c)
+{
+ char nibble = c & 0xF;
+ return nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
+}
+
+inline char upperNibbleToASCIIHexDigit(char c)
+{
+ char nibble = (c >> 4) & 0xF;
+ return nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
+}
+
+}
+
+using WTF::isASCII;
+using WTF::isASCIIAlpha;
+using WTF::isASCIIAlphanumeric;
+using WTF::isASCIIDigit;
+using WTF::isASCIIHexDigit;
+using WTF::isASCIILower;
+using WTF::isASCIIOctalDigit;
+using WTF::isASCIIPrintable;
+using WTF::isASCIISpace;
+using WTF::isASCIIUpper;
+using WTF::toASCIIHexValue;
+using WTF::toASCIILower;
+using WTF::toASCIIUpper;
+using WTF::lowerNibbleToASCIIHexDigit;
+using WTF::upperNibbleToASCIIHexDigit;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/AVLTree.h b/Source/JavaScriptCore/wtf/AVLTree.h
new file mode 100644
index 000000000..ec8a63951
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/AVLTree.h
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Based on Abstract AVL Tree Template v1.5 by Walt Karas
+ * <http://geocities.com/wkaras/gen_cpp/avl_tree.html>.
+ *
+ * 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 AVL_TREE_H_
+#define AVL_TREE_H_
+
+#include "Assertions.h"
+#include <wtf/FixedArray.h>
+
+namespace WTF {
+
+// Here is the reference class for BSet.
+//
+// class BSet
+// {
+// public:
+//
+// class ANY_bitref
+// {
+// public:
+// operator bool ();
+// void operator = (bool b);
+// };
+//
+// // Does not have to initialize bits.
+// BSet();
+//
+// // Must return a valid value for index when 0 <= index < maxDepth
+// ANY_bitref operator [] (unsigned index);
+//
+// // Set all bits to 1.
+// void set();
+//
+// // Set all bits to 0.
+// void reset();
+// };
+
+template<unsigned maxDepth>
+class AVLTreeDefaultBSet {
+public:
+ bool& operator[](unsigned i) { ASSERT(i < maxDepth); return m_data[i]; }
+ void set() { for (unsigned i = 0; i < maxDepth; ++i) m_data[i] = true; }
+ void reset() { for (unsigned i = 0; i < maxDepth; ++i) m_data[i] = false; }
+
+private:
+ FixedArray<bool, maxDepth> m_data;
+};
+
+// How to determine maxDepth:
+// d Minimum number of nodes
+// 2 2
+// 3 4
+// 4 7
+// 5 12
+// 6 20
+// 7 33
+// 8 54
+// 9 88
+// 10 143
+// 11 232
+// 12 376
+// 13 609
+// 14 986
+// 15 1,596
+// 16 2,583
+// 17 4,180
+// 18 6,764
+// 19 10,945
+// 20 17,710
+// 21 28,656
+// 22 46,367
+// 23 75,024
+// 24 121,392
+// 25 196,417
+// 26 317,810
+// 27 514,228
+// 28 832,039
+// 29 1,346,268
+// 30 2,178,308
+// 31 3,524,577
+// 32 5,702,886
+// 33 9,227,464
+// 34 14,930,351
+// 35 24,157,816
+// 36 39,088,168
+// 37 63,245,985
+// 38 102,334,154
+// 39 165,580,140
+// 40 267,914,295
+// 41 433,494,436
+// 42 701,408,732
+// 43 1,134,903,169
+// 44 1,836,311,902
+// 45 2,971,215,072
+//
+// E.g., if, in a particular instantiation, the maximum number of nodes in a tree instance is 1,000,000, the maximum depth should be 28.
+// You pick 28 because MN(28) is 832,039, which is less than or equal to 1,000,000, and MN(29) is 1,346,268, which is strictly greater than 1,000,000.
+
+template <class Abstractor, unsigned maxDepth = 32, class BSet = AVLTreeDefaultBSet<maxDepth> >
+class AVLTree {
+public:
+
+ typedef typename Abstractor::key key;
+ typedef typename Abstractor::handle handle;
+ typedef typename Abstractor::size size;
+
+ enum SearchType {
+ EQUAL = 1,
+ LESS = 2,
+ GREATER = 4,
+ LESS_EQUAL = EQUAL | LESS,
+ GREATER_EQUAL = EQUAL | GREATER
+ };
+
+
+ Abstractor& abstractor() { return abs; }
+
+ inline handle insert(handle h);
+
+ inline handle search(key k, SearchType st = EQUAL);
+ inline handle search_least();
+ inline handle search_greatest();
+
+ inline handle remove(key k);
+
+ inline handle subst(handle new_node);
+
+ void purge() { abs.root = null(); }
+
+ bool is_empty() { return abs.root == null(); }
+
+ AVLTree() { abs.root = null(); }
+
+ class Iterator {
+ public:
+
+ // Initialize depth to invalid value, to indicate iterator is
+ // invalid. (Depth is zero-base.)
+ Iterator() { depth = ~0U; }
+
+ void start_iter(AVLTree &tree, key k, SearchType st = EQUAL)
+ {
+ // Mask of high bit in an int.
+ const int MASK_HIGH_BIT = (int) ~ ((~ (unsigned) 0) >> 1);
+
+ // Save the tree that we're going to iterate through in a
+ // member variable.
+ tree_ = &tree;
+
+ int cmp, target_cmp;
+ handle h = tree_->abs.root;
+ unsigned d = 0;
+
+ depth = ~0U;
+
+ if (h == null())
+ // Tree is empty.
+ return;
+
+ if (st & LESS)
+ // Key can be greater than key of starting node.
+ target_cmp = 1;
+ else if (st & GREATER)
+ // Key can be less than key of starting node.
+ target_cmp = -1;
+ else
+ // Key must be same as key of starting node.
+ target_cmp = 0;
+
+ for (;;) {
+ cmp = cmp_k_n(k, h);
+ if (cmp == 0) {
+ if (st & EQUAL) {
+ // Equal node was sought and found as starting node.
+ depth = d;
+ break;
+ }
+ cmp = -target_cmp;
+ } else if (target_cmp != 0) {
+ if (!((cmp ^ target_cmp) & MASK_HIGH_BIT)) {
+ // cmp and target_cmp are both negative or both positive.
+ depth = d;
+ }
+ }
+ h = cmp < 0 ? get_lt(h) : get_gt(h);
+ if (h == null())
+ break;
+ branch[d] = cmp > 0;
+ path_h[d++] = h;
+ }
+ }
+
+ void start_iter_least(AVLTree &tree)
+ {
+ tree_ = &tree;
+
+ handle h = tree_->abs.root;
+
+ depth = ~0U;
+
+ branch.reset();
+
+ while (h != null()) {
+ if (depth != ~0U)
+ path_h[depth] = h;
+ depth++;
+ h = get_lt(h);
+ }
+ }
+
+ void start_iter_greatest(AVLTree &tree)
+ {
+ tree_ = &tree;
+
+ handle h = tree_->abs.root;
+
+ depth = ~0U;
+
+ branch.set();
+
+ while (h != null()) {
+ if (depth != ~0U)
+ path_h[depth] = h;
+ depth++;
+ h = get_gt(h);
+ }
+ }
+
+ handle operator*()
+ {
+ if (depth == ~0U)
+ return null();
+
+ return depth == 0 ? tree_->abs.root : path_h[depth - 1];
+ }
+
+ void operator++()
+ {
+ if (depth != ~0U) {
+ handle h = get_gt(**this);
+ if (h == null()) {
+ do {
+ if (depth == 0) {
+ depth = ~0U;
+ break;
+ }
+ depth--;
+ } while (branch[depth]);
+ } else {
+ branch[depth] = true;
+ path_h[depth++] = h;
+ for (;;) {
+ h = get_lt(h);
+ if (h == null())
+ break;
+ branch[depth] = false;
+ path_h[depth++] = h;
+ }
+ }
+ }
+ }
+
+ void operator--()
+ {
+ if (depth != ~0U) {
+ handle h = get_lt(**this);
+ if (h == null())
+ do {
+ if (depth == 0) {
+ depth = ~0U;
+ break;
+ }
+ depth--;
+ } while (!branch[depth]);
+ else {
+ branch[depth] = false;
+ path_h[depth++] = h;
+ for (;;) {
+ h = get_gt(h);
+ if (h == null())
+ break;
+ branch[depth] = true;
+ path_h[depth++] = h;
+ }
+ }
+ }
+ }
+
+ void operator++(int) { ++(*this); }
+ void operator--(int) { --(*this); }
+
+ protected:
+
+ // Tree being iterated over.
+ AVLTree *tree_;
+
+ // Records a path into the tree. If branch[n] is true, indicates
+ // take greater branch from the nth node in the path, otherwise
+ // take the less branch. branch[0] gives branch from root, and
+ // so on.
+ BSet branch;
+
+ // Zero-based depth of path into tree.
+ unsigned depth;
+
+ // Handles of nodes in path from root to current node (returned by *).
+ handle path_h[maxDepth - 1];
+
+ int cmp_k_n(key k, handle h) { return tree_->abs.compare_key_node(k, h); }
+ int cmp_n_n(handle h1, handle h2) { return tree_->abs.compare_node_node(h1, h2); }
+ handle get_lt(handle h) { return tree_->abs.get_less(h); }
+ handle get_gt(handle h) { return tree_->abs.get_greater(h); }
+ handle null() { return tree_->abs.null(); }
+ };
+
+ template<typename fwd_iter>
+ bool build(fwd_iter p, size num_nodes)
+ {
+ if (num_nodes == 0) {
+ abs.root = null();
+ return true;
+ }
+
+ // Gives path to subtree being built. If branch[N] is false, branch
+ // less from the node at depth N, if true branch greater.
+ BSet branch;
+
+ // If rem[N] is true, then for the current subtree at depth N, it's
+ // greater subtree has one more node than it's less subtree.
+ BSet rem;
+
+ // Depth of root node of current subtree.
+ unsigned depth = 0;
+
+ // Number of nodes in current subtree.
+ size num_sub = num_nodes;
+
+ // The algorithm relies on a stack of nodes whose less subtree has
+ // been built, but whose right subtree has not yet been built. The
+ // stack is implemented as linked list. The nodes are linked
+ // together by having the "greater" handle of a node set to the
+ // next node in the list. "less_parent" is the handle of the first
+ // node in the list.
+ handle less_parent = null();
+
+ // h is root of current subtree, child is one of its children.
+ handle h, child;
+
+ for (;;) {
+ while (num_sub > 2) {
+ // Subtract one for root of subtree.
+ num_sub--;
+ rem[depth] = !!(num_sub & 1);
+ branch[depth++] = false;
+ num_sub >>= 1;
+ }
+
+ if (num_sub == 2) {
+ // Build a subtree with two nodes, slanting to greater.
+ // I arbitrarily chose to always have the extra node in the
+ // greater subtree when there is an odd number of nodes to
+ // split between the two subtrees.
+
+ h = *p;
+ p++;
+ child = *p;
+ p++;
+ set_lt(child, null());
+ set_gt(child, null());
+ set_bf(child, 0);
+ set_gt(h, child);
+ set_lt(h, null());
+ set_bf(h, 1);
+ } else { // num_sub == 1
+ // Build a subtree with one node.
+
+ h = *p;
+ p++;
+ set_lt(h, null());
+ set_gt(h, null());
+ set_bf(h, 0);
+ }
+
+ while (depth) {
+ depth--;
+ if (!branch[depth])
+ // We've completed a less subtree.
+ break;
+
+ // We've completed a greater subtree, so attach it to
+ // its parent (that is less than it). We pop the parent
+ // off the stack of less parents.
+ child = h;
+ h = less_parent;
+ less_parent = get_gt(h);
+ set_gt(h, child);
+ // num_sub = 2 * (num_sub - rem[depth]) + rem[depth] + 1
+ num_sub <<= 1;
+ num_sub += 1 - rem[depth];
+ if (num_sub & (num_sub - 1))
+ // num_sub is not a power of 2
+ set_bf(h, 0);
+ else
+ // num_sub is a power of 2
+ set_bf(h, 1);
+ }
+
+ if (num_sub == num_nodes)
+ // We've completed the full tree.
+ break;
+
+ // The subtree we've completed is the less subtree of the
+ // next node in the sequence.
+
+ child = h;
+ h = *p;
+ p++;
+ set_lt(h, child);
+
+ // Put h into stack of less parents.
+ set_gt(h, less_parent);
+ less_parent = h;
+
+ // Proceed to creating greater than subtree of h.
+ branch[depth] = true;
+ num_sub += rem[depth++];
+
+ } // end for (;;)
+
+ abs.root = h;
+
+ return true;
+ }
+
+protected:
+
+ friend class Iterator;
+
+ // Create a class whose sole purpose is to take advantage of
+ // the "empty member" optimization.
+ struct abs_plus_root : public Abstractor {
+ // The handle of the root element in the AVL tree.
+ handle root;
+ };
+
+ abs_plus_root abs;
+
+
+ handle get_lt(handle h) { return abs.get_less(h); }
+ void set_lt(handle h, handle lh) { abs.set_less(h, lh); }
+
+ handle get_gt(handle h) { return abs.get_greater(h); }
+ void set_gt(handle h, handle gh) { abs.set_greater(h, gh); }
+
+ int get_bf(handle h) { return abs.get_balance_factor(h); }
+ void set_bf(handle h, int bf) { abs.set_balance_factor(h, bf); }
+
+ int cmp_k_n(key k, handle h) { return abs.compare_key_node(k, h); }
+ int cmp_n_n(handle h1, handle h2) { return abs.compare_node_node(h1, h2); }
+
+ handle null() { return abs.null(); }
+
+private:
+
+ // Balances subtree, returns handle of root node of subtree
+ // after balancing.
+ handle balance(handle bal_h)
+ {
+ handle deep_h;
+
+ // Either the "greater than" or the "less than" subtree of
+ // this node has to be 2 levels deeper (or else it wouldn't
+ // need balancing).
+
+ if (get_bf(bal_h) > 0) {
+ // "Greater than" subtree is deeper.
+
+ deep_h = get_gt(bal_h);
+
+ if (get_bf(deep_h) < 0) {
+ handle old_h = bal_h;
+ bal_h = get_lt(deep_h);
+
+ set_gt(old_h, get_lt(bal_h));
+ set_lt(deep_h, get_gt(bal_h));
+ set_lt(bal_h, old_h);
+ set_gt(bal_h, deep_h);
+
+ int bf = get_bf(bal_h);
+ if (bf != 0) {
+ if (bf > 0) {
+ set_bf(old_h, -1);
+ set_bf(deep_h, 0);
+ } else {
+ set_bf(deep_h, 1);
+ set_bf(old_h, 0);
+ }
+ set_bf(bal_h, 0);
+ } else {
+ set_bf(old_h, 0);
+ set_bf(deep_h, 0);
+ }
+ } else {
+ set_gt(bal_h, get_lt(deep_h));
+ set_lt(deep_h, bal_h);
+ if (get_bf(deep_h) == 0) {
+ set_bf(deep_h, -1);
+ set_bf(bal_h, 1);
+ } else {
+ set_bf(deep_h, 0);
+ set_bf(bal_h, 0);
+ }
+ bal_h = deep_h;
+ }
+ } else {
+ // "Less than" subtree is deeper.
+
+ deep_h = get_lt(bal_h);
+
+ if (get_bf(deep_h) > 0) {
+ handle old_h = bal_h;
+ bal_h = get_gt(deep_h);
+ set_lt(old_h, get_gt(bal_h));
+ set_gt(deep_h, get_lt(bal_h));
+ set_gt(bal_h, old_h);
+ set_lt(bal_h, deep_h);
+
+ int bf = get_bf(bal_h);
+ if (bf != 0) {
+ if (bf < 0) {
+ set_bf(old_h, 1);
+ set_bf(deep_h, 0);
+ } else {
+ set_bf(deep_h, -1);
+ set_bf(old_h, 0);
+ }
+ set_bf(bal_h, 0);
+ } else {
+ set_bf(old_h, 0);
+ set_bf(deep_h, 0);
+ }
+ } else {
+ set_lt(bal_h, get_gt(deep_h));
+ set_gt(deep_h, bal_h);
+ if (get_bf(deep_h) == 0) {
+ set_bf(deep_h, 1);
+ set_bf(bal_h, -1);
+ } else {
+ set_bf(deep_h, 0);
+ set_bf(bal_h, 0);
+ }
+ bal_h = deep_h;
+ }
+ }
+
+ return bal_h;
+ }
+
+};
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::insert(handle h)
+{
+ set_lt(h, null());
+ set_gt(h, null());
+ set_bf(h, 0);
+
+ if (abs.root == null())
+ abs.root = h;
+ else {
+ // Last unbalanced node encountered in search for insertion point.
+ handle unbal = null();
+ // Parent of last unbalanced node.
+ handle parent_unbal = null();
+ // Balance factor of last unbalanced node.
+ int unbal_bf;
+
+ // Zero-based depth in tree.
+ unsigned depth = 0, unbal_depth = 0;
+
+ // Records a path into the tree. If branch[n] is true, indicates
+ // take greater branch from the nth node in the path, otherwise
+ // take the less branch. branch[0] gives branch from root, and
+ // so on.
+ BSet branch;
+
+ handle hh = abs.root;
+ handle parent = null();
+ int cmp;
+
+ do {
+ if (get_bf(hh) != 0) {
+ unbal = hh;
+ parent_unbal = parent;
+ unbal_depth = depth;
+ }
+ cmp = cmp_n_n(h, hh);
+ if (cmp == 0)
+ // Duplicate key.
+ return hh;
+ parent = hh;
+ hh = cmp < 0 ? get_lt(hh) : get_gt(hh);
+ branch[depth++] = cmp > 0;
+ } while (hh != null());
+
+ // Add node to insert as leaf of tree.
+ if (cmp < 0)
+ set_lt(parent, h);
+ else
+ set_gt(parent, h);
+
+ depth = unbal_depth;
+
+ if (unbal == null())
+ hh = abs.root;
+ else {
+ cmp = branch[depth++] ? 1 : -1;
+ unbal_bf = get_bf(unbal);
+ if (cmp < 0)
+ unbal_bf--;
+ else // cmp > 0
+ unbal_bf++;
+ hh = cmp < 0 ? get_lt(unbal) : get_gt(unbal);
+ if ((unbal_bf != -2) && (unbal_bf != 2)) {
+ // No rebalancing of tree is necessary.
+ set_bf(unbal, unbal_bf);
+ unbal = null();
+ }
+ }
+
+ if (hh != null())
+ while (h != hh) {
+ cmp = branch[depth++] ? 1 : -1;
+ if (cmp < 0) {
+ set_bf(hh, -1);
+ hh = get_lt(hh);
+ } else { // cmp > 0
+ set_bf(hh, 1);
+ hh = get_gt(hh);
+ }
+ }
+
+ if (unbal != null()) {
+ unbal = balance(unbal);
+ if (parent_unbal == null())
+ abs.root = unbal;
+ else {
+ depth = unbal_depth - 1;
+ cmp = branch[depth] ? 1 : -1;
+ if (cmp < 0)
+ set_lt(parent_unbal, unbal);
+ else // cmp > 0
+ set_gt(parent_unbal, unbal);
+ }
+ }
+ }
+
+ return h;
+}
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::search(key k, typename AVLTree<Abstractor, maxDepth, BSet>::SearchType st)
+{
+ const int MASK_HIGH_BIT = (int) ~ ((~ (unsigned) 0) >> 1);
+
+ int cmp, target_cmp;
+ handle match_h = null();
+ handle h = abs.root;
+
+ if (st & LESS)
+ target_cmp = 1;
+ else if (st & GREATER)
+ target_cmp = -1;
+ else
+ target_cmp = 0;
+
+ while (h != null()) {
+ cmp = cmp_k_n(k, h);
+ if (cmp == 0) {
+ if (st & EQUAL) {
+ match_h = h;
+ break;
+ }
+ cmp = -target_cmp;
+ } else if (target_cmp != 0)
+ if (!((cmp ^ target_cmp) & MASK_HIGH_BIT))
+ // cmp and target_cmp are both positive or both negative.
+ match_h = h;
+ h = cmp < 0 ? get_lt(h) : get_gt(h);
+ }
+
+ return match_h;
+}
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::search_least()
+{
+ handle h = abs.root, parent = null();
+
+ while (h != null()) {
+ parent = h;
+ h = get_lt(h);
+ }
+
+ return parent;
+}
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::search_greatest()
+{
+ handle h = abs.root, parent = null();
+
+ while (h != null()) {
+ parent = h;
+ h = get_gt(h);
+ }
+
+ return parent;
+}
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::remove(key k)
+{
+ // Zero-based depth in tree.
+ unsigned depth = 0, rm_depth;
+
+ // Records a path into the tree. If branch[n] is true, indicates
+ // take greater branch from the nth node in the path, otherwise
+ // take the less branch. branch[0] gives branch from root, and
+ // so on.
+ BSet branch;
+
+ handle h = abs.root;
+ handle parent = null(), child;
+ int cmp, cmp_shortened_sub_with_path = 0;
+
+ for (;;) {
+ if (h == null())
+ // No node in tree with given key.
+ return null();
+ cmp = cmp_k_n(k, h);
+ if (cmp == 0)
+ // Found node to remove.
+ break;
+ parent = h;
+ h = cmp < 0 ? get_lt(h) : get_gt(h);
+ branch[depth++] = cmp > 0;
+ cmp_shortened_sub_with_path = cmp;
+ }
+ handle rm = h;
+ handle parent_rm = parent;
+ rm_depth = depth;
+
+ // If the node to remove is not a leaf node, we need to get a
+ // leaf node, or a node with a single leaf as its child, to put
+ // in the place of the node to remove. We will get the greatest
+ // node in the less subtree (of the node to remove), or the least
+ // node in the greater subtree. We take the leaf node from the
+ // deeper subtree, if there is one.
+
+ if (get_bf(h) < 0) {
+ child = get_lt(h);
+ branch[depth] = false;
+ cmp = -1;
+ } else {
+ child = get_gt(h);
+ branch[depth] = true;
+ cmp = 1;
+ }
+ depth++;
+
+ if (child != null()) {
+ cmp = -cmp;
+ do {
+ parent = h;
+ h = child;
+ if (cmp < 0) {
+ child = get_lt(h);
+ branch[depth] = false;
+ } else {
+ child = get_gt(h);
+ branch[depth] = true;
+ }
+ depth++;
+ } while (child != null());
+
+ if (parent == rm)
+ // Only went through do loop once. Deleted node will be replaced
+ // in the tree structure by one of its immediate children.
+ cmp_shortened_sub_with_path = -cmp;
+ else
+ cmp_shortened_sub_with_path = cmp;
+
+ // Get the handle of the opposite child, which may not be null.
+ child = cmp > 0 ? get_lt(h) : get_gt(h);
+ }
+
+ if (parent == null())
+ // There were only 1 or 2 nodes in this tree.
+ abs.root = child;
+ else if (cmp_shortened_sub_with_path < 0)
+ set_lt(parent, child);
+ else
+ set_gt(parent, child);
+
+ // "path" is the parent of the subtree being eliminated or reduced
+ // from a depth of 2 to 1. If "path" is the node to be removed, we
+ // set path to the node we're about to poke into the position of the
+ // node to be removed.
+ handle path = parent == rm ? h : parent;
+
+ if (h != rm) {
+ // Poke in the replacement for the node to be removed.
+ set_lt(h, get_lt(rm));
+ set_gt(h, get_gt(rm));
+ set_bf(h, get_bf(rm));
+ if (parent_rm == null())
+ abs.root = h;
+ else {
+ depth = rm_depth - 1;
+ if (branch[depth])
+ set_gt(parent_rm, h);
+ else
+ set_lt(parent_rm, h);
+ }
+ }
+
+ if (path != null()) {
+ // Create a temporary linked list from the parent of the path node
+ // to the root node.
+ h = abs.root;
+ parent = null();
+ depth = 0;
+ while (h != path) {
+ if (branch[depth++]) {
+ child = get_gt(h);
+ set_gt(h, parent);
+ } else {
+ child = get_lt(h);
+ set_lt(h, parent);
+ }
+ parent = h;
+ h = child;
+ }
+
+ // Climb from the path node to the root node using the linked
+ // list, restoring the tree structure and rebalancing as necessary.
+ bool reduced_depth = true;
+ int bf;
+ cmp = cmp_shortened_sub_with_path;
+ for (;;) {
+ if (reduced_depth) {
+ bf = get_bf(h);
+ if (cmp < 0)
+ bf++;
+ else // cmp > 0
+ bf--;
+ if ((bf == -2) || (bf == 2)) {
+ h = balance(h);
+ bf = get_bf(h);
+ } else
+ set_bf(h, bf);
+ reduced_depth = (bf == 0);
+ }
+ if (parent == null())
+ break;
+ child = h;
+ h = parent;
+ cmp = branch[--depth] ? 1 : -1;
+ if (cmp < 0) {
+ parent = get_lt(h);
+ set_lt(h, child);
+ } else {
+ parent = get_gt(h);
+ set_gt(h, child);
+ }
+ }
+ abs.root = h;
+ }
+
+ return rm;
+}
+
+template <class Abstractor, unsigned maxDepth, class BSet>
+inline typename AVLTree<Abstractor, maxDepth, BSet>::handle
+AVLTree<Abstractor, maxDepth, BSet>::subst(handle new_node)
+{
+ handle h = abs.root;
+ handle parent = null();
+ int cmp, last_cmp;
+
+ /* Search for node already in tree with same key. */
+ for (;;) {
+ if (h == null())
+ /* No node in tree with same key as new node. */
+ return null();
+ cmp = cmp_n_n(new_node, h);
+ if (cmp == 0)
+ /* Found the node to substitute new one for. */
+ break;
+ last_cmp = cmp;
+ parent = h;
+ h = cmp < 0 ? get_lt(h) : get_gt(h);
+ }
+
+ /* Copy tree housekeeping fields from node in tree to new node. */
+ set_lt(new_node, get_lt(h));
+ set_gt(new_node, get_gt(h));
+ set_bf(new_node, get_bf(h));
+
+ if (parent == null())
+ /* New node is also new root. */
+ abs.root = new_node;
+ else {
+ /* Make parent point to new node. */
+ if (last_cmp < 0)
+ set_lt(parent, new_node);
+ else
+ set_gt(parent, new_node);
+ }
+
+ return h;
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/Alignment.h b/Source/JavaScriptCore/wtf/Alignment.h
new file mode 100644
index 000000000..d42b307ed
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Alignment.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WTF_Alignment_h
+#define WTF_Alignment_h
+
+#include "Platform.h"
+#include <algorithm>
+
+namespace WTF {
+
+#if COMPILER(GCC) || COMPILER(MINGW) || COMPILER(RVCT) || COMPILER(GCCE)
+ #define WTF_ALIGN_OF(type) __alignof__(type)
+ #define WTF_ALIGNED(variable_type, variable, n) variable_type variable __attribute__((__aligned__(n)))
+#elif COMPILER(MSVC)
+ #define WTF_ALIGN_OF(type) __alignof(type)
+ #define WTF_ALIGNED(variable_type, variable, n) __declspec(align(n)) variable_type variable
+#else
+ #error WTF_ALIGN macros need alignment control.
+#endif
+
+#if COMPILER(GCC) && !COMPILER(INTEL) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303)
+ typedef char __attribute__((__may_alias__)) AlignedBufferChar;
+#else
+ typedef char AlignedBufferChar;
+#endif
+
+ template<size_t size, size_t alignment> struct AlignedBuffer;
+ template<size_t size> struct AlignedBuffer<size, 1> { AlignedBufferChar buffer[size]; };
+ template<size_t size> struct AlignedBuffer<size, 2> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 2); };
+ template<size_t size> struct AlignedBuffer<size, 4> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 4); };
+ template<size_t size> struct AlignedBuffer<size, 8> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 8); };
+ template<size_t size> struct AlignedBuffer<size, 16> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 16); };
+ template<size_t size> struct AlignedBuffer<size, 32> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 32); };
+ template<size_t size> struct AlignedBuffer<size, 64> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 64); };
+
+ template <size_t size, size_t alignment>
+ void swap(AlignedBuffer<size, alignment>& a, AlignedBuffer<size, alignment>& b)
+ {
+ for (size_t i = 0; i < size; ++i)
+ std::swap(a.buffer[i], b.buffer[i]);
+ }
+
+}
+
+#endif // WTF_Alignment_h
diff --git a/Source/JavaScriptCore/wtf/AlwaysInline.h b/Source/JavaScriptCore/wtf/AlwaysInline.h
new file mode 100644
index 000000000..de12ddd90
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/AlwaysInline.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2005, 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.
+ *
+ */
+
+/* This file is no longer necessary, since all the functionality has been moved to Compiler.h. */
+
+#include "Platform.h"
diff --git a/Source/JavaScriptCore/wtf/ArrayBuffer.cpp b/Source/JavaScriptCore/wtf/ArrayBuffer.cpp
new file mode 100644
index 000000000..45cfa1deb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ArrayBuffer.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ArrayBuffer.h"
+
+#include "ArrayBufferView.h"
+
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+bool ArrayBuffer::transfer(ArrayBufferContents& result, Vector<RefPtr<ArrayBufferView> >& neuteredViews)
+{
+ RefPtr<ArrayBuffer> keepAlive(this);
+
+ if (!m_contents.m_data) {
+ result.m_data = 0;
+ return false;
+ }
+
+ m_contents.transfer(result);
+
+ while (m_firstView) {
+ ArrayBufferView* current = m_firstView;
+ removeView(current);
+ current->neuter();
+ neuteredViews.append(current);
+ }
+ return true;
+}
+
+void ArrayBuffer::addView(ArrayBufferView* view)
+{
+ view->m_buffer = this;
+ view->m_prevView = 0;
+ view->m_nextView = m_firstView;
+ if (m_firstView)
+ m_firstView->m_prevView = view;
+ m_firstView = view;
+}
+
+void ArrayBuffer::removeView(ArrayBufferView* view)
+{
+ ASSERT(this == view->m_buffer);
+ if (view->m_nextView)
+ view->m_nextView->m_prevView = view->m_prevView;
+ if (view->m_prevView)
+ view->m_prevView->m_nextView = view->m_nextView;
+ if (m_firstView == view)
+ m_firstView = view->m_nextView;
+ view->m_prevView = view->m_nextView = 0;
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/ArrayBuffer.h b/Source/JavaScriptCore/wtf/ArrayBuffer.h
new file mode 100644
index 000000000..ee95f5bc6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ArrayBuffer.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ArrayBuffer_h
+#define ArrayBuffer_h
+
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+class ArrayBuffer;
+class ArrayBufferView;
+
+class ArrayBufferContents {
+ WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
+public:
+ ArrayBufferContents()
+ : m_data(0)
+ , m_sizeInBytes(0)
+ { }
+
+ inline ~ArrayBufferContents();
+
+ void* data() { return m_data; }
+ unsigned sizeInBytes() { return m_sizeInBytes; }
+
+private:
+ ArrayBufferContents(void* data, unsigned sizeInBytes)
+ : m_data(data)
+ , m_sizeInBytes(sizeInBytes)
+ { }
+
+ friend class ArrayBuffer;
+
+ static inline void tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents&);
+ void transfer(ArrayBufferContents& other)
+ {
+ ASSERT(!other.m_data);
+ other.m_data = m_data;
+ other.m_sizeInBytes = m_sizeInBytes;
+ m_data = 0;
+ m_sizeInBytes = 0;
+ }
+
+ void* m_data;
+ unsigned m_sizeInBytes;
+};
+
+class ArrayBuffer : public RefCounted<ArrayBuffer> {
+public:
+ static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
+ static inline PassRefPtr<ArrayBuffer> create(ArrayBuffer*);
+ static inline PassRefPtr<ArrayBuffer> create(const void* source, unsigned byteLength);
+ static inline PassRefPtr<ArrayBuffer> create(ArrayBufferContents&);
+
+ inline void* data();
+ inline const void* data() const;
+ inline unsigned byteLength() const;
+
+ inline PassRefPtr<ArrayBuffer> slice(int begin, int end) const;
+ inline PassRefPtr<ArrayBuffer> slice(int begin) const;
+
+ void addView(ArrayBufferView*);
+ void removeView(ArrayBufferView*);
+
+ bool transfer(ArrayBufferContents&, Vector<RefPtr<ArrayBufferView> >& neuteredViews);
+ bool isNeutered() { return !m_contents.m_data; }
+
+ ~ArrayBuffer() { }
+
+private:
+ inline ArrayBuffer(ArrayBufferContents&);
+ inline PassRefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
+ inline unsigned clampIndex(int index) const;
+ static inline int clampValue(int x, int left, int right);
+
+ ArrayBufferContents m_contents;
+ ArrayBufferView* m_firstView;
+};
+
+int ArrayBuffer::clampValue(int x, int left, int right)
+{
+ ASSERT(left <= right);
+ if (x < left)
+ x = left;
+ if (right < x)
+ x = right;
+ return x;
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize)
+{
+ ArrayBufferContents contents;
+ ArrayBufferContents::tryAllocate(numElements, elementByteSize, contents);
+ if (!contents.m_data)
+ return 0;
+ return adoptRef(new ArrayBuffer(contents));
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBuffer* other)
+{
+ return ArrayBuffer::create(other->data(), other->byteLength());
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
+{
+ ArrayBufferContents contents;
+ ArrayBufferContents::tryAllocate(byteLength, 1, contents);
+ if (!contents.m_data)
+ return 0;
+ RefPtr<ArrayBuffer> buffer = adoptRef(new ArrayBuffer(contents));
+ memcpy(buffer->data(), source, byteLength);
+ return buffer.release();
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents& contents)
+{
+ return adoptRef(new ArrayBuffer(contents));
+}
+
+ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents)
+ : m_firstView(0)
+{
+ contents.transfer(m_contents);
+}
+
+void* ArrayBuffer::data()
+{
+ return m_contents.m_data;
+}
+
+const void* ArrayBuffer::data() const
+{
+ return m_contents.m_data;
+}
+
+unsigned ArrayBuffer::byteLength() const
+{
+ return m_contents.m_sizeInBytes;
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const
+{
+ return sliceImpl(clampIndex(begin), clampIndex(end));
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const
+{
+ return sliceImpl(clampIndex(begin), byteLength());
+}
+
+PassRefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
+{
+ unsigned size = begin <= end ? end - begin : 0;
+ return ArrayBuffer::create(static_cast<const char*>(data()) + begin, size);
+}
+
+unsigned ArrayBuffer::clampIndex(int index) const
+{
+ unsigned currentLength = byteLength();
+ if (index < 0)
+ index = currentLength + index;
+ return clampValue(index, 0, currentLength);
+}
+
+void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents& result)
+{
+ // Do not allow 32-bit overflow of the total size.
+ // FIXME: Why not? The tryFastCalloc function already checks its arguments,
+ // and will fail if there is any overflow, so why should we include a
+ // redudant unnecessarily restrictive check here?
+ if (numElements) {
+ unsigned totalSize = numElements * elementByteSize;
+ if (totalSize / numElements != elementByteSize) {
+ result.m_data = 0;
+ return;
+ }
+ }
+ if (WTF::tryFastCalloc(numElements, elementByteSize).getValue(result.m_data)) {
+ result.m_sizeInBytes = numElements * elementByteSize;
+ return;
+ }
+ result.m_data = 0;
+}
+
+ArrayBufferContents::~ArrayBufferContents()
+{
+ WTF::fastFree(m_data);
+}
+
+} // namespace WTF
+
+using WTF::ArrayBuffer;
+
+#endif // ArrayBuffer_h
diff --git a/Source/JavaScriptCore/wtf/ArrayBufferView.cpp b/Source/JavaScriptCore/wtf/ArrayBufferView.cpp
new file mode 100644
index 000000000..67dbdcf8c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ArrayBufferView.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ArrayBufferView.h"
+
+#include "ArrayBuffer.h"
+
+namespace WTF {
+
+ArrayBufferView::ArrayBufferView(PassRefPtr<ArrayBuffer> buffer,
+ unsigned byteOffset)
+ : m_byteOffset(byteOffset)
+ , m_buffer(buffer)
+{
+ m_baseAddress = m_buffer ? (static_cast<char*>(m_buffer->data()) + m_byteOffset) : 0;
+ if (m_buffer)
+ m_buffer->addView(this);
+}
+
+ArrayBufferView::~ArrayBufferView()
+{
+ if (m_buffer)
+ m_buffer->removeView(this);
+}
+
+void ArrayBufferView::neuter()
+{
+ m_buffer = 0;
+ m_byteOffset = 0;
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/ArrayBufferView.h b/Source/JavaScriptCore/wtf/ArrayBufferView.h
new file mode 100644
index 000000000..ccb7fd348
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ArrayBufferView.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ArrayBufferView_h
+#define ArrayBufferView_h
+
+#include "ArrayBuffer.h"
+
+#include <algorithm>
+#include <limits.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WTF {
+
+class ArrayBufferView : public RefCounted<ArrayBufferView> {
+ public:
+ virtual bool isByteArray() const { return false; }
+ virtual bool isUnsignedByteArray() const { return false; }
+ virtual bool isShortArray() const { return false; }
+ virtual bool isUnsignedShortArray() const { return false; }
+ virtual bool isIntArray() const { return false; }
+ virtual bool isUnsignedIntArray() const { return false; }
+ virtual bool isFloatArray() const { return false; }
+ virtual bool isDoubleArray() const { return false; }
+ virtual bool isDataView() const { return false; }
+
+ PassRefPtr<ArrayBuffer> buffer() const
+ {
+ return m_buffer;
+ }
+
+ void* baseAddress() const
+ {
+ return m_baseAddress;
+ }
+
+ unsigned byteOffset() const
+ {
+ return m_byteOffset;
+ }
+
+ virtual unsigned byteLength() const = 0;
+
+ virtual ~ArrayBufferView();
+
+ protected:
+ ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset);
+
+ inline bool setImpl(ArrayBufferView*, unsigned byteOffset);
+
+ inline bool setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset);
+
+ inline bool zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength);
+
+ static inline void calculateOffsetAndLength(int start, int end, unsigned arraySize,
+ unsigned* offset, unsigned* length);
+
+ // Helper to verify that a given sub-range of an ArrayBuffer is
+ // within range.
+ template <typename T>
+ static bool verifySubRange(PassRefPtr<ArrayBuffer> buffer,
+ unsigned byteOffset,
+ unsigned numElements)
+ {
+ if (!buffer)
+ return false;
+ if (sizeof(T) > 1 && byteOffset % sizeof(T))
+ return false;
+ if (byteOffset > buffer->byteLength())
+ return false;
+ unsigned remainingElements = (buffer->byteLength() - byteOffset) / sizeof(T);
+ if (numElements > remainingElements)
+ return false;
+ return true;
+ }
+
+ // Input offset is in number of elements from this array's view;
+ // output offset is in number of bytes from the underlying buffer's view.
+ template <typename T>
+ static void clampOffsetAndNumElements(PassRefPtr<ArrayBuffer> buffer,
+ unsigned arrayByteOffset,
+ unsigned *offset,
+ unsigned *numElements)
+ {
+ unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T);
+ if (*offset > maxOffset) {
+ *offset = buffer->byteLength();
+ *numElements = 0;
+ return;
+ }
+ *offset = arrayByteOffset + *offset * sizeof(T);
+ *offset = std::min(buffer->byteLength(), *offset);
+ unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T);
+ *numElements = std::min(remainingElements, *numElements);
+ }
+
+ virtual void neuter();
+
+ // This is the address of the ArrayBuffer's storage, plus the byte offset.
+ void* m_baseAddress;
+
+ unsigned m_byteOffset;
+
+ private:
+ friend class ArrayBuffer;
+ RefPtr<ArrayBuffer> m_buffer;
+ ArrayBufferView* m_prevView;
+ ArrayBufferView* m_nextView;
+};
+
+bool ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset)
+{
+ if (byteOffset > byteLength()
+ || byteOffset + array->byteLength() > byteLength()
+ || byteOffset + array->byteLength() < byteOffset) {
+ // Out of range offset or overflow
+ return false;
+ }
+
+ char* base = static_cast<char*>(baseAddress());
+ memmove(base + byteOffset, array->baseAddress(), array->byteLength());
+ return true;
+}
+
+bool ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset)
+{
+ if (byteOffset > byteLength()
+ || byteOffset + dataByteLength > byteLength()
+ || byteOffset + dataByteLength < byteOffset) {
+ // Out of range offset or overflow
+ return false;
+ }
+
+ char* base = static_cast<char*>(baseAddress());
+ memmove(base + byteOffset, data, dataByteLength);
+ return true;
+}
+
+bool ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength)
+{
+ if (byteOffset > byteLength()
+ || byteOffset + rangeByteLength > byteLength()
+ || byteOffset + rangeByteLength < byteOffset) {
+ // Out of range offset or overflow
+ return false;
+ }
+
+ char* base = static_cast<char*>(baseAddress());
+ memset(base + byteOffset, 0, rangeByteLength);
+ return true;
+}
+
+void ArrayBufferView::calculateOffsetAndLength(int start, int end, unsigned arraySize,
+ unsigned* offset, unsigned* length)
+{
+ if (start < 0)
+ start += arraySize;
+ if (start < 0)
+ start = 0;
+ if (end < 0)
+ end += arraySize;
+ if (end < 0)
+ end = 0;
+ if (end < start)
+ end = start;
+ *offset = static_cast<unsigned>(start);
+ *length = static_cast<unsigned>(end - start);
+}
+
+} // namespace WTF
+
+using WTF::ArrayBufferView;
+
+#endif // ArrayBufferView_h
diff --git a/Source/JavaScriptCore/wtf/Assertions.cpp b/Source/JavaScriptCore/wtf/Assertions.cpp
new file mode 100644
index 000000000..de062ce25
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Assertions.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, 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.
+ *
+ * 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.
+ */
+
+// The vprintf_stderr_common function triggers this error in the Mac build.
+// Feel free to remove this pragma if this file builds on Mac.
+// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
+// we need to place this directive before any data or functions are defined.
+#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
+
+#include "config.h"
+#include "Assertions.h"
+
+#include "OwnArrayPtr.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#if PLATFORM(MAC)
+#include <CoreFoundation/CFString.h>
+#include <asl.h>
+#endif
+
+#if COMPILER(MSVC) && !OS(WINCE)
+#include <crtdbg.h>
+#endif
+
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
+#if OS(DARWIN) || OS(LINUX)
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#endif
+
+#if PLATFORM(BLACKBERRY)
+#include <BlackBerryPlatformLog.h>
+#endif
+
+extern "C" {
+
+WTF_ATTRIBUTE_PRINTF(1, 0)
+static void vprintf_stderr_common(const char* format, va_list args)
+{
+#if PLATFORM(MAC)
+ if (strstr(format, "%@")) {
+ CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
+
+ int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
+ char* buffer = (char*)malloc(length + 1);
+
+ CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);
+
+#if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION)
+ asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer);
+#endif
+ fputs(buffer, stderr);
+
+ free(buffer);
+ CFRelease(str);
+ CFRelease(cfFormat);
+ return;
+ }
+
+#if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION)
+ va_list copyOfArgs;
+ va_copy(copyOfArgs, args);
+ asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
+ va_end(copyOfArgs);
+#endif
+
+ // Fall through to write to stderr in the same manner as other platforms.
+
+#elif PLATFORM(BLACKBERRY)
+ BlackBerry::Platform::logV(BlackBerry::Platform::LogLevelInfo, format, args);
+#elif HAVE(ISDEBUGGERPRESENT)
+ if (IsDebuggerPresent()) {
+ size_t size = 1024;
+
+ do {
+ char* buffer = (char*)malloc(size);
+
+ if (buffer == NULL)
+ break;
+
+ if (_vsnprintf(buffer, size, format, args) != -1) {
+#if OS(WINCE)
+ // WinCE only supports wide chars
+ wchar_t* wideBuffer = (wchar_t*)malloc(size * sizeof(wchar_t));
+ if (wideBuffer == NULL)
+ break;
+ for (unsigned int i = 0; i < size; ++i) {
+ if (!(wideBuffer[i] = buffer[i]))
+ break;
+ }
+ OutputDebugStringW(wideBuffer);
+ free(wideBuffer);
+#else
+ OutputDebugStringA(buffer);
+#endif
+ free(buffer);
+ break;
+ }
+
+ free(buffer);
+ size *= 2;
+ } while (size > 1024);
+ }
+#endif
+ vfprintf(stderr, format, args);
+}
+
+#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+static void vprintf_stderr_with_prefix(const char* prefix, const char* format, va_list args)
+{
+ size_t prefixLength = strlen(prefix);
+ size_t formatLength = strlen(format);
+ OwnArrayPtr<char> formatWithPrefix = adoptArrayPtr(new char[prefixLength + formatLength + 1]);
+ memcpy(formatWithPrefix.get(), prefix, prefixLength);
+ memcpy(formatWithPrefix.get() + prefixLength, format, formatLength);
+ formatWithPrefix[prefixLength + formatLength] = 0;
+
+ vprintf_stderr_common(formatWithPrefix.get(), args);
+}
+
+static void vprintf_stderr_with_trailing_newline(const char* format, va_list args)
+{
+ size_t formatLength = strlen(format);
+ if (formatLength && format[formatLength - 1] == '\n') {
+ vprintf_stderr_common(format, args);
+ return;
+ }
+
+ OwnArrayPtr<char> formatWithNewline = adoptArrayPtr(new char[formatLength + 2]);
+ memcpy(formatWithNewline.get(), format, formatLength);
+ formatWithNewline[formatLength] = '\n';
+ formatWithNewline[formatLength + 1] = 0;
+
+ vprintf_stderr_common(formatWithNewline.get(), args);
+}
+
+#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
+#pragma GCC diagnostic pop
+#endif
+
+WTF_ATTRIBUTE_PRINTF(1, 2)
+static void printf_stderr_common(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_common(format, args);
+ va_end(args);
+}
+
+static void printCallSite(const char* file, int line, const char* function)
+{
+#if OS(WINDOWS) && !OS(WINCE) && defined(_DEBUG)
+ _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
+#else
+ // By using this format, which matches the format used by MSVC for compiler errors, developers
+ // using Visual Studio can double-click the file/line number in the Output Window to have the
+ // editor navigate to that line of code. It seems fine for other developers, too.
+ printf_stderr_common("%s(%d) : %s\n", file, line, function);
+#endif
+}
+
+void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
+{
+ if (assertion)
+ printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
+ else
+ printf_stderr_common("SHOULD NEVER BE REACHED\n");
+ printCallSite(file, line, function);
+}
+
+void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args);
+ va_end(args);
+ printf_stderr_common("\n%s\n", assertion);
+ printCallSite(file, line, function);
+}
+
+void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
+{
+ printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
+ printCallSite(file, line, function);
+}
+
+void WTFGetBacktrace(void** stack, int* size)
+{
+#if OS(DARWIN) || OS(LINUX)
+ *size = backtrace(stack, *size);
+#elif OS(WINDOWS) && !OS(WINCE)
+ // The CaptureStackBackTrace function is available in XP, but it is not defined
+ // in the Windows Server 2003 R2 Platform SDK. So, we'll grab the function
+ // through GetProcAddress.
+ typedef WORD (NTAPI* RtlCaptureStackBackTraceFunc)(DWORD, DWORD, PVOID*, PDWORD);
+ HMODULE kernel32 = ::GetModuleHandleW(L"Kernel32.dll");
+ if (!kernel32) {
+ *size = 0;
+ return;
+ }
+ RtlCaptureStackBackTraceFunc captureStackBackTraceFunc = reinterpret_cast<RtlCaptureStackBackTraceFunc>(
+ ::GetProcAddress(kernel32, "RtlCaptureStackBackTrace"));
+ if (captureStackBackTraceFunc)
+ *size = captureStackBackTraceFunc(0, *size, stack, 0);
+ else
+ *size = 0;
+#else
+ *size = 0;
+#endif
+}
+
+void WTFReportBacktrace()
+{
+ static const int framesToShow = 31;
+ static const int framesToSkip = 2;
+ void* samples[framesToShow + framesToSkip];
+ int frames = framesToShow + framesToSkip;
+
+ WTFGetBacktrace(samples, &frames);
+
+ for (int i = framesToSkip; i < frames; ++i) {
+ const char* mangledName = 0;
+ char* cxaDemangled = 0;
+
+#if !PLATFORM(GTK) && !PLATFORM(QT) && (OS(DARWIN) || OS(LINUX))
+ Dl_info info;
+ if (dladdr(samples[i], &info) && info.dli_sname)
+ mangledName = info.dli_sname;
+ if (mangledName)
+ cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
+#endif
+ const int frameNumber = i - framesToSkip + 1;
+ if (mangledName || cxaDemangled)
+ printf_stderr_common("%-3d %p %s\n", frameNumber, samples[i], cxaDemangled ? cxaDemangled : mangledName);
+ else
+ printf_stderr_common("%-3d %p\n", frameNumber, samples[i]);
+ free(cxaDemangled);
+ }
+}
+
+void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_with_prefix("FATAL ERROR: ", format, args);
+ va_end(args);
+ printf_stderr_common("\n");
+ printCallSite(file, line, function);
+}
+
+void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_with_prefix("ERROR: ", format, args);
+ va_end(args);
+ printf_stderr_common("\n");
+ printCallSite(file, line, function);
+}
+
+void WTFLog(WTFLogChannel* channel, const char* format, ...)
+{
+ if (channel->state != WTFLogChannelOn)
+ return;
+
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_with_trailing_newline(format, args);
+ va_end(args);
+}
+
+void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
+{
+ if (channel->state != WTFLogChannelOn)
+ return;
+
+ va_list args;
+ va_start(args, format);
+ vprintf_stderr_with_trailing_newline(format, args);
+ va_end(args);
+
+ printCallSite(file, line, function);
+}
+
+} // extern "C"
diff --git a/Source/JavaScriptCore/wtf/Assertions.h b/Source/JavaScriptCore/wtf/Assertions.h
new file mode 100644
index 000000000..2b3d794a4
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Assertions.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 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_Assertions_h
+#define WTF_Assertions_h
+
+/*
+ no namespaces because this file has to be includable from C and Objective-C
+
+ Note, this file uses many GCC extensions, but it should be compatible with
+ C, Objective C, C++, and Objective C++.
+
+ For non-debug builds, everything is disabled by default.
+ Defining any of the symbols explicitly prevents this from having any effect.
+
+ MSVC7 note: variadic macro support was added in MSVC8, so for now we disable
+ those macros in MSVC7. For more info, see the MSDN document on variadic
+ macros here:
+
+ http://msdn2.microsoft.com/en-us/library/ms177415(VS.80).aspx
+*/
+
+#include "Platform.h"
+
+#include <stddef.h>
+
+#if !COMPILER(MSVC)
+#include <inttypes.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_OR_LOWER)
+#define HAVE_VARIADIC_MACRO 0
+#else
+#define HAVE_VARIADIC_MACRO 1
+#endif
+
+#ifndef BACKTRACE_DISABLED
+#define BACKTRACE_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#endif
+
+#ifndef ASSERT_DISABLED
+#define ASSERT_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#endif
+
+#ifndef ASSERT_MSG_DISABLED
+#if HAVE(VARIADIC_MACRO)
+#define ASSERT_MSG_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#else
+#define ASSERT_MSG_DISABLED 1
+#endif
+#endif
+
+#ifndef ASSERT_ARG_DISABLED
+#define ASSERT_ARG_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#endif
+
+#ifndef FATAL_DISABLED
+#if HAVE(VARIADIC_MACRO)
+#define FATAL_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#else
+#define FATAL_DISABLED 1
+#endif
+#endif
+
+#ifndef ERROR_DISABLED
+#if HAVE(VARIADIC_MACRO)
+#define ERROR_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#else
+#define ERROR_DISABLED 1
+#endif
+#endif
+
+#ifndef LOG_DISABLED
+#if HAVE(VARIADIC_MACRO)
+#define LOG_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#else
+#define LOG_DISABLED 1
+#endif
+#endif
+
+#if COMPILER(GCC)
+#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define WTF_PRETTY_FUNCTION __FUNCTION__
+#endif
+
+/* WTF logging functions can process %@ in the format string to log a NSObject* but the printf format attribute
+ emits a warning when %@ is used in the format string. Until <rdar://problem/5195437> is resolved we can't include
+ the attribute when being used from Objective-C code in case it decides to use %@. */
+#if COMPILER(GCC) && !defined(__OBJC__)
+#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(printf, formatStringArgument, extraArguments)))
+#else
+#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments)
+#endif
+
+/* These helper functions are always declared, but not necessarily always defined if the corresponding function is disabled. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum { WTFLogChannelOff, WTFLogChannelOn } WTFLogChannelState;
+
+typedef struct {
+ unsigned mask;
+ const char *defaultName;
+ WTFLogChannelState state;
+} WTFLogChannel;
+
+WTF_EXPORT_PRIVATE void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
+WTF_EXPORT_PRIVATE void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
+WTF_EXPORT_PRIVATE void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion);
+WTF_EXPORT_PRIVATE void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
+WTF_EXPORT_PRIVATE void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
+WTF_EXPORT_PRIVATE void WTFLog(WTFLogChannel*, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+WTF_EXPORT_PRIVATE void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel*, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
+
+WTF_EXPORT_PRIVATE void WTFGetBacktrace(void** stack, int* size);
+WTF_EXPORT_PRIVATE void WTFReportBacktrace();
+
+#ifdef __cplusplus
+}
+#endif
+
+/* 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 COMPILER(CLANG)
+#define CRASH() do { \
+ WTFReportBacktrace(); \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ __builtin_trap(); \
+} while (false)
+#else
+#define CRASH() do { \
+ WTFReportBacktrace(); \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
+} while (false)
+#endif
+#endif
+
+#if COMPILER(CLANG)
+#define NO_RETURN_DUE_TO_CRASH NO_RETURN
+#else
+#define NO_RETURN_DUE_TO_CRASH
+#endif
+
+
+/* BACKTRACE
+
+ Print a backtrace to the same location as ASSERT messages.
+*/
+
+#if BACKTRACE_DISABLED
+
+#define BACKTRACE() ((void)0)
+
+#else
+
+#define BACKTRACE() do { \
+ WTFReportBacktrace(); \
+} while(false)
+
+#endif
+
+/* 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. */
+#include <windows.h>
+#undef min
+#undef max
+#undef ERROR
+#endif
+
+#if OS(WINDOWS)
+/* FIXME: Change to use something other than ASSERT to avoid this conflict with the underlying platform */
+#undef ASSERT
+#endif
+
+#if ASSERT_DISABLED
+
+#define ASSERT(assertion) ((void)0)
+#define ASSERT_AT(assertion, file, line, function) ((void)0)
+#define ASSERT_NOT_REACHED() ((void)0)
+#define NO_RETURN_DUE_TO_ASSERT
+
+#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
+
+#define ASSERT(assertion) do \
+ if (!(assertion)) { \
+ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
+ CRASH(); \
+ } \
+while (0)
+
+#define ASSERT_AT(assertion, file, line, function) do \
+ if (!(assertion)) { \
+ WTFReportAssertionFailure(file, line, function, #assertion); \
+ CRASH(); \
+ } \
+while (0)
+
+#define ASSERT_NOT_REACHED() do { \
+ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
+ CRASH(); \
+} while (0)
+
+#define ASSERT_UNUSED(variable, assertion) ASSERT(assertion)
+
+#define NO_RETURN_DUE_TO_ASSERT NO_RETURN_DUE_TO_CRASH
+
+#endif
+
+/* ASSERT_WITH_MESSAGE */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define ASSERT_WITH_MESSAGE(assertion) ((void)0)
+#elif ASSERT_MSG_DISABLED
+#define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0)
+#else
+#define ASSERT_WITH_MESSAGE(assertion, ...) do \
+ if (!(assertion)) { \
+ WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
+ CRASH(); \
+ } \
+while (0)
+#endif
+
+/* ASSERT_WITH_MESSAGE_UNUSED */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion) ((void)0)
+#elif ASSERT_MSG_DISABLED
+#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+template<typename T>
+inline void assertWithMessageUnused(T& x) { (void)x; }
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) (assertWithMessageUnused(variable))
+#else
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) ((void)variable)
+#endif
+#else
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) do \
+ if (!(assertion)) { \
+ WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
+ CRASH(); \
+ } \
+while (0)
+#endif
+
+
+/* ASSERT_ARG */
+
+#if ASSERT_ARG_DISABLED
+
+#define ASSERT_ARG(argName, assertion) ((void)0)
+
+#else
+
+#define ASSERT_ARG(argName, assertion) do \
+ if (!(assertion)) { \
+ WTFReportArgumentAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #argName, #assertion); \
+ CRASH(); \
+ } \
+while (0)
+
+#endif
+
+/* COMPILE_ASSERT */
+#ifndef COMPILE_ASSERT
+#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
+#endif
+
+/* FATAL */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define FATAL() ((void)0)
+#elif FATAL_DISABLED
+#define FATAL(...) ((void)0)
+#else
+#define FATAL(...) do { \
+ WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__); \
+ CRASH(); \
+} while (0)
+#endif
+
+/* LOG_ERROR */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define LOG_ERROR() ((void)0)
+#elif ERROR_DISABLED
+#define LOG_ERROR(...) ((void)0)
+#else
+#define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__)
+#endif
+
+/* LOG */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define LOG() ((void)0)
+#elif LOG_DISABLED
+#define LOG(channel, ...) ((void)0)
+#else
+#define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
+#define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel)
+#define JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) prefix ## channel
+#endif
+
+/* LOG_VERBOSE */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define LOG_VERBOSE(channel) ((void)0)
+#elif LOG_DISABLED
+#define LOG_VERBOSE(channel, ...) ((void)0)
+#else
+#define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
+#endif
+
+#if ENABLE(GC_VALIDATION)
+#define ASSERT_GC_OBJECT_LOOKS_VALID(cell) do { \
+ if (!(cell))\
+ CRASH();\
+ if (cell->unvalidatedStructure()->unvalidatedStructure() != cell->unvalidatedStructure()->unvalidatedStructure()->unvalidatedStructure())\
+ CRASH();\
+} while (0)
+
+#define ASSERT_GC_OBJECT_INHERITS(object, classInfo) do {\
+ ASSERT_GC_OBJECT_LOOKS_VALID(object); \
+ if (!object->inherits(classInfo)) \
+ CRASH();\
+} while (0)
+
+#else
+#define ASSERT_GC_OBJECT_LOOKS_VALID(cell) do { (void)cell; } while (0)
+#define ASSERT_GC_OBJECT_INHERITS(object, classInfo) do { (void)object; (void)classInfo; } while (0)
+#endif
+
+#if COMPILER(CLANG)
+#define ASSERT_HAS_TRIVIAL_DESTRUCTOR(klass) COMPILE_ASSERT(__has_trivial_destructor(klass), klass##_has_trivial_destructor_check)
+#else
+#define ASSERT_HAS_TRIVIAL_DESTRUCTOR(klass)
+#endif
+
+#endif /* WTF_Assertions_h */
diff --git a/Source/JavaScriptCore/wtf/Atomics.h b/Source/JavaScriptCore/wtf/Atomics.h
new file mode 100644
index 000000000..5e10460c6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Atomics.h
@@ -0,0 +1,196 @@
+/*
+ * 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"
+#include "StdLibExtras.h"
+#include "UnusedParam.h"
+
+#if OS(WINDOWS)
+#include <windows.h>
+#elif OS(DARWIN)
+#include <libkern/OSAtomic.h>
+#elif OS(QNX)
+#include <atomic.h>
+#elif OS(ANDROID)
+#include <sys/atomics.h>
+#elif COMPILER(GCC)
+#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_THREADSAFEREFCOUNTED 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_THREADSAFEREFCOUNTED 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(QNX)
+#define WTF_USE_LOCKFREE_THREADSAFEREFCOUNTED 1
+
+// Note, atomic_{add, sub}_value() return the previous value of addend's content.
+inline int atomicIncrement(int volatile* addend) { return static_cast<int>(atomic_add_value(reinterpret_cast<unsigned volatile*>(addend), 1)) + 1; }
+inline int atomicDecrement(int volatile* addend) { return static_cast<int>(atomic_sub_value(reinterpret_cast<unsigned volatile*>(addend), 1)) - 1; }
+
+#elif OS(ANDROID)
+
+inline int atomicIncrement(int volatile* addend) { return __atomic_inc(addend); }
+inline int atomicDecrement(int volatile* addend) { return __atomic_dec(addend); }
+
+#elif COMPILER(GCC) && !CPU(SPARC64) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc
+#define WTF_USE_LOCKFREE_THREADSAFEREFCOUNTED 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
+
+inline bool weakCompareAndSwap(unsigned* location, unsigned expected, unsigned newValue)
+{
+#if ENABLE(COMPARE_AND_SWAP)
+ bool result;
+#if CPU(X86) || CPU(X86_64)
+ asm volatile(
+ "lock; cmpxchgl %3, %2\n\t"
+ "sete %1"
+ : "+a"(expected), "=q"(result), "+m"(*location)
+ : "r"(newValue)
+ : "memory"
+ );
+#elif CPU(ARM_THUMB2)
+ unsigned tmp;
+ asm volatile(
+ "movw %1, #1\n\t"
+ "ldrex %2, %0\n\t"
+ "cmp %3, %2\n\t"
+ "bne.n 0f\n\t"
+ "strex %1, %4, %0\n\t"
+ "0:"
+ : "+m"(*location), "=&r"(result), "=&r"(tmp)
+ : "r"(expected), "r"(newValue)
+ : "memory");
+ result = !result;
+#else
+#error "Bad architecture for compare and swap."
+#endif
+ return result;
+#else
+ UNUSED_PARAM(location);
+ UNUSED_PARAM(expected);
+ UNUSED_PARAM(newValue);
+ CRASH();
+ return 0;
+#endif
+}
+
+inline bool weakCompareAndSwap(void*volatile* location, void* expected, void* newValue)
+{
+#if ENABLE(COMPARE_AND_SWAP)
+#if CPU(X86_64)
+ bool result;
+ asm volatile(
+ "lock; cmpxchgq %3, %2\n\t"
+ "sete %1"
+ : "+a"(expected), "=q"(result), "+m"(*location)
+ : "r"(newValue)
+ : "memory"
+ );
+ return result;
+#else
+ return weakCompareAndSwap(bitwise_cast<unsigned*>(location), bitwise_cast<unsigned>(expected), bitwise_cast<unsigned>(newValue));
+#endif
+#else // ENABLE(COMPARE_AND_SWAP)
+ UNUSED_PARAM(location);
+ UNUSED_PARAM(expected);
+ UNUSED_PARAM(newValue);
+ CRASH();
+ return 0;
+#endif // ENABLE(COMPARE_AND_SWAP)
+}
+
+inline bool weakCompareAndSwap(volatile uintptr_t* location, uintptr_t expected, uintptr_t newValue)
+{
+ return weakCompareAndSwap(reinterpret_cast<void*volatile*>(location), reinterpret_cast<void*>(expected), reinterpret_cast<void*>(newValue));
+}
+
+} // namespace WTF
+
+#if USE(LOCKFREE_THREADSAFEREFCOUNTED)
+using WTF::atomicDecrement;
+using WTF::atomicIncrement;
+#endif
+
+#endif // Atomics_h
diff --git a/Source/JavaScriptCore/wtf/BitVector.cpp b/Source/JavaScriptCore/wtf/BitVector.cpp
new file mode 100644
index 000000000..49dc21129
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BitVector.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 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 "BitVector.h"
+
+#include <algorithm>
+#include <string.h>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+void BitVector::setSlow(const BitVector& other)
+{
+ uintptr_t newBitsOrPointer;
+ if (other.isInline())
+ newBitsOrPointer = other.m_bitsOrPointer;
+ else {
+ OutOfLineBits* newOutOfLineBits = OutOfLineBits::create(other.size());
+ memcpy(newOutOfLineBits->bits(), other.bits(), byteCount(other.size()));
+ newBitsOrPointer = bitwise_cast<uintptr_t>(newOutOfLineBits) >> 1;
+ }
+ if (!isInline())
+ OutOfLineBits::destroy(outOfLineBits());
+ m_bitsOrPointer = newBitsOrPointer;
+}
+
+void BitVector::resize(size_t numBits)
+{
+ if (numBits <= maxInlineBits()) {
+ if (isInline())
+ return;
+
+ OutOfLineBits* myOutOfLineBits = outOfLineBits();
+ m_bitsOrPointer = makeInlineBits(*myOutOfLineBits->bits());
+ OutOfLineBits::destroy(myOutOfLineBits);
+ return;
+ }
+
+ resizeOutOfLine(numBits);
+}
+
+void BitVector::clearAll()
+{
+ if (isInline())
+ m_bitsOrPointer = makeInlineBits(0);
+ else
+ memset(outOfLineBits()->bits(), 0, byteCount(size()));
+}
+
+BitVector::OutOfLineBits* BitVector::OutOfLineBits::create(size_t numBits)
+{
+ numBits = (numBits + bitsInPointer() - 1) & ~(bitsInPointer() - 1);
+ size_t size = sizeof(OutOfLineBits) + sizeof(uintptr_t) * (numBits / bitsInPointer());
+ OutOfLineBits* result = new (NotNull, fastMalloc(size)) OutOfLineBits(numBits);
+ return result;
+}
+
+void BitVector::OutOfLineBits::destroy(OutOfLineBits* outOfLineBits)
+{
+ fastFree(outOfLineBits);
+}
+
+void BitVector::resizeOutOfLine(size_t numBits)
+{
+ ASSERT(numBits > maxInlineBits());
+ OutOfLineBits* newOutOfLineBits = OutOfLineBits::create(numBits);
+ if (isInline()) {
+ // Make sure that all of the bits are zero in case we do a no-op resize.
+ *newOutOfLineBits->bits() = m_bitsOrPointer & ~(static_cast<uintptr_t>(1) << maxInlineBits());
+ } else {
+ if (numBits > size()) {
+ size_t oldNumWords = outOfLineBits()->numWords();
+ size_t newNumWords = newOutOfLineBits->numWords();
+ memcpy(newOutOfLineBits->bits(), outOfLineBits()->bits(), oldNumWords * sizeof(void*));
+ memset(newOutOfLineBits->bits() + oldNumWords, 0, (newNumWords - oldNumWords) * sizeof(void*));
+ } else
+ memcpy(newOutOfLineBits->bits(), outOfLineBits()->bits(), newOutOfLineBits->numWords() * sizeof(void*));
+ OutOfLineBits::destroy(outOfLineBits());
+ }
+ m_bitsOrPointer = bitwise_cast<uintptr_t>(newOutOfLineBits) >> 1;
+}
+
+#ifndef NDEBUG
+void BitVector::dump(FILE* out)
+{
+ for (size_t i = 0; i < size(); ++i) {
+ if (get(i))
+ fprintf(out, "1");
+ else
+ fprintf(out, "-");
+ }
+}
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/BitVector.h b/Source/JavaScriptCore/wtf/BitVector.h
new file mode 100644
index 000000000..109d3ffcf
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BitVector.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2011 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 BitVector_h
+#define BitVector_h
+
+#include <wtf/Assertions.h>
+#include <wtf/StdLibExtras.h>
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+namespace WTF {
+
+// This is a space-efficient, resizeable bitvector class. In the common case it
+// occupies one word, but if necessary, it will inflate this one word to point
+// to a single chunk of out-of-line allocated storage to store an arbitrary number
+// of bits.
+//
+// - The bitvector remembers the bound of how many bits can be stored, but this
+// may be slightly greater (by as much as some platform-specific constant)
+// than the last argument passed to ensureSize().
+//
+// - The bitvector can resize itself automatically (set, clear, get) or can be used
+// in a manual mode, which is faster (quickSet, quickClear, quickGet, ensureSize).
+//
+// - Accesses ASSERT that you are within bounds.
+//
+// - Bits are automatically initialized to zero.
+//
+// On the other hand, this BitVector class may not be the fastest around, since
+// it does conditionals on every get/set/clear. But it is great if you need to
+// juggle a lot of variable-length BitVectors and you're worried about wasting
+// space.
+
+class BitVector {
+public:
+ BitVector()
+ : m_bitsOrPointer(makeInlineBits(0))
+ {
+ }
+
+ explicit BitVector(size_t numBits)
+ : m_bitsOrPointer(makeInlineBits(0))
+ {
+ ensureSize(numBits);
+ }
+
+ BitVector(const BitVector& other)
+ : m_bitsOrPointer(makeInlineBits(0))
+ {
+ (*this) = other;
+ }
+
+
+ ~BitVector()
+ {
+ if (isInline())
+ return;
+ OutOfLineBits::destroy(outOfLineBits());
+ }
+
+ BitVector& operator=(const BitVector& other)
+ {
+ if (isInline() && other.isInline())
+ m_bitsOrPointer = other.m_bitsOrPointer;
+ else
+ setSlow(other);
+ return *this;
+ }
+
+ size_t size() const
+ {
+ if (isInline())
+ return maxInlineBits();
+ return outOfLineBits()->numBits();
+ }
+
+ void ensureSize(size_t numBits)
+ {
+ if (numBits <= size())
+ return;
+ resizeOutOfLine(numBits);
+ }
+
+ // Like ensureSize(), but supports reducing the size of the bitvector.
+ void resize(size_t numBits);
+
+ void clearAll();
+
+ bool quickGet(size_t bit) const
+ {
+ ASSERT(bit < size());
+ return !!(bits()[bit / bitsInPointer()] & (static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1))));
+ }
+
+ void quickSet(size_t bit)
+ {
+ ASSERT(bit < size());
+ bits()[bit / bitsInPointer()] |= (static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1)));
+ }
+
+ void quickClear(size_t bit)
+ {
+ ASSERT(bit < size());
+ bits()[bit / bitsInPointer()] &= ~(static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1)));
+ }
+
+ void quickSet(size_t bit, bool value)
+ {
+ if (value)
+ quickSet(bit);
+ else
+ quickClear(bit);
+ }
+
+ bool get(size_t bit) const
+ {
+ if (bit >= size())
+ return false;
+ return quickGet(bit);
+ }
+
+ void set(size_t bit)
+ {
+ ensureSize(bit + 1);
+ quickSet(bit);
+ }
+
+ void clear(size_t bit)
+ {
+ if (bit >= size())
+ return;
+ quickClear(bit);
+ }
+
+ void set(size_t bit, bool value)
+ {
+ if (value)
+ set(bit);
+ else
+ clear(bit);
+ }
+
+#ifndef NDEBUG
+ void dump(FILE* out);
+#endif
+
+private:
+ static unsigned bitsInPointer()
+ {
+ return sizeof(void*) << 3;
+ }
+
+ static unsigned maxInlineBits()
+ {
+ return bitsInPointer() - 1;
+ }
+
+ static size_t byteCount(size_t bitCount)
+ {
+ return (bitCount + 7) >> 3;
+ }
+
+ static uintptr_t makeInlineBits(uintptr_t bits)
+ {
+ ASSERT(!(bits & (static_cast<uintptr_t>(1) << maxInlineBits())));
+ return bits | (static_cast<uintptr_t>(1) << maxInlineBits());
+ }
+
+ class OutOfLineBits {
+ public:
+ size_t numBits() const { return m_numBits; }
+ size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); }
+ uintptr_t* bits() { return bitwise_cast<uintptr_t*>(this + 1); }
+ const uintptr_t* bits() const { return bitwise_cast<const uintptr_t*>(this + 1); }
+
+ static OutOfLineBits* create(size_t numBits);
+
+ static void destroy(OutOfLineBits*);
+
+ private:
+ OutOfLineBits(size_t numBits)
+ : m_numBits(numBits)
+ {
+ }
+
+ size_t m_numBits;
+ };
+
+ bool isInline() const { return m_bitsOrPointer >> maxInlineBits(); }
+
+ const OutOfLineBits* outOfLineBits() const { return bitwise_cast<const OutOfLineBits*>(m_bitsOrPointer << 1); }
+ OutOfLineBits* outOfLineBits() { return bitwise_cast<OutOfLineBits*>(m_bitsOrPointer << 1); }
+
+ void resizeOutOfLine(size_t numBits);
+ void setSlow(const BitVector& other);
+
+ uintptr_t* bits()
+ {
+ if (isInline())
+ return &m_bitsOrPointer;
+ return outOfLineBits()->bits();
+ }
+
+ const uintptr_t* bits() const
+ {
+ if (isInline())
+ return &m_bitsOrPointer;
+ return outOfLineBits()->bits();
+ }
+
+ uintptr_t m_bitsOrPointer;
+};
+
+} // namespace WTF
+
+using WTF::BitVector;
+
+#endif // BitVector_h
diff --git a/Source/JavaScriptCore/wtf/Bitmap.h b/Source/JavaScriptCore/wtf/Bitmap.h
new file mode 100644
index 000000000..d7e2528a3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Bitmap.h
@@ -0,0 +1,225 @@
+/*
+ * 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 "Atomics.h"
+#include "FixedArray.h"
+#include "StdLibExtras.h"
+#include <stdint.h>
+#include <string.h>
+
+namespace WTF {
+
+enum BitmapAtomicMode {
+ // This makes concurrentTestAndSet behave just like testAndSet.
+ BitmapNotAtomic,
+
+ // This makes concurrentTestAndSet use compareAndSwap, so that it's
+ // atomic even when used concurrently.
+ BitmapAtomic
+};
+
+template<size_t size, BitmapAtomicMode atomicMode = BitmapNotAtomic>
+class Bitmap {
+private:
+ typedef uint32_t WordType;
+
+public:
+ Bitmap();
+
+ bool get(size_t) const;
+ void set(size_t);
+ bool testAndSet(size_t);
+ bool testAndClear(size_t);
+ bool concurrentTestAndSet(size_t);
+ bool concurrentTestAndClear(size_t);
+ size_t nextPossiblyUnset(size_t) const;
+ void clear(size_t);
+ void clearAll();
+ int64_t findRunOfZeros(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, BitmapAtomicMode atomicMode>
+inline Bitmap<size, atomicMode>::Bitmap()
+{
+ clearAll();
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline bool Bitmap<size, atomicMode>::get(size_t n) const
+{
+ return !!(bits[n / wordSize] & (one << (n % wordSize)));
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline void Bitmap<size, atomicMode>::set(size_t n)
+{
+ bits[n / wordSize] |= (one << (n % wordSize));
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline bool Bitmap<size, atomicMode>::testAndSet(size_t n)
+{
+ WordType mask = one << (n % wordSize);
+ size_t index = n / wordSize;
+ bool result = bits[index] & mask;
+ bits[index] |= mask;
+ return result;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline bool Bitmap<size, atomicMode>::testAndClear(size_t n)
+{
+ WordType mask = one << (n % wordSize);
+ size_t index = n / wordSize;
+ bool result = bits[index] & mask;
+ bits[index] &= ~mask;
+ return result;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline bool Bitmap<size, atomicMode>::concurrentTestAndSet(size_t n)
+{
+ if (atomicMode == BitmapNotAtomic)
+ return testAndSet(n);
+
+ ASSERT(atomicMode == BitmapAtomic);
+
+ WordType mask = one << (n % wordSize);
+ size_t index = n / wordSize;
+ WordType* wordPtr = bits.data() + index;
+ WordType oldValue;
+ do {
+ oldValue = *wordPtr;
+ if (oldValue & mask)
+ return true;
+ } while (!weakCompareAndSwap(wordPtr, oldValue, oldValue | mask));
+ return false;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline bool Bitmap<size, atomicMode>::concurrentTestAndClear(size_t n)
+{
+ if (atomicMode == BitmapNotAtomic)
+ return testAndClear(n);
+
+ ASSERT(atomicMode == BitmapAtomic);
+
+ WordType mask = one << (n % wordSize);
+ size_t index = n / wordSize;
+ WordType* wordPtr = bits.data() + index;
+ WordType oldValue;
+ do {
+ oldValue = *wordPtr;
+ if (!(oldValue & mask))
+ return false;
+ } while (!weakCompareAndSwap(wordPtr, oldValue, oldValue & ~mask));
+ return true;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline void Bitmap<size, atomicMode>::clear(size_t n)
+{
+ bits[n / wordSize] &= ~(one << (n % wordSize));
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline void Bitmap<size, atomicMode>::clearAll()
+{
+ memset(bits.data(), 0, sizeof(bits));
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline size_t Bitmap<size, atomicMode>::nextPossiblyUnset(size_t start) const
+{
+ if (!~bits[start / wordSize])
+ return ((start / wordSize) + 1) * wordSize;
+ return start + 1;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline int64_t Bitmap<size, atomicMode>::findRunOfZeros(size_t runLength) const
+{
+ if (!runLength)
+ runLength = 1;
+
+ for (size_t i = 0; i <= (size - runLength) ; i++) {
+ bool found = true;
+ for (size_t j = i; j <= (i + runLength - 1) ; j++) {
+ if (get(j)) {
+ found = false;
+ break;
+ }
+ }
+ if (found)
+ return i;
+ }
+ return -1;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline size_t Bitmap<size, atomicMode>::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, BitmapAtomicMode atomicMode>
+inline size_t Bitmap<size, atomicMode>::isEmpty() const
+{
+ for (size_t i = 0; i < words; ++i)
+ if (bits[i])
+ return false;
+ return true;
+}
+
+template<size_t size, BitmapAtomicMode atomicMode>
+inline size_t Bitmap<size, atomicMode>::isFull() const
+{
+ for (size_t i = 0; i < words; ++i)
+ if (~bits[i])
+ return false;
+ return true;
+}
+
+}
+#endif
diff --git a/Source/JavaScriptCore/wtf/BlockStack.h b/Source/JavaScriptCore/wtf/BlockStack.h
new file mode 100644
index 000000000..61e108db3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BlockStack.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 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 BlockStack_h
+#define BlockStack_h
+
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+template <typename T> class BlockStack {
+public:
+ static const size_t blockSize = 4096;
+ static const size_t blockLength = blockSize / sizeof(T);
+
+ BlockStack();
+ ~BlockStack();
+
+ T* grow();
+ void shrink(T*);
+
+ const Vector<T*>& blocks();
+
+private:
+ Vector<T*> m_blocks;
+ T* m_spareBlock; // Used to avoid thrash at block boundaries.
+};
+
+template <typename T> BlockStack<T>::BlockStack()
+ : m_spareBlock(0)
+{
+}
+
+template <typename T> BlockStack<T>::~BlockStack()
+{
+ if (m_spareBlock)
+ fastFree(m_spareBlock);
+ for (size_t i = 0; i < m_blocks.size(); ++i)
+ fastFree(m_blocks[i]);
+}
+
+template <typename T> inline const Vector<T*>& BlockStack<T>::blocks()
+{
+ return m_blocks;
+}
+
+template <typename T> T* BlockStack<T>::grow()
+{
+ T* block = m_spareBlock ? m_spareBlock : static_cast<T*>(fastMalloc(blockSize));
+ m_spareBlock = 0;
+
+ m_blocks.append(block);
+ return block;
+}
+
+template <typename T> void BlockStack<T>::shrink(T* newEnd)
+{
+ ASSERT(newEnd != m_blocks.last() + blockLength);
+ m_spareBlock = m_blocks.last();
+ m_blocks.removeLast();
+
+ while (m_blocks.last() + blockLength != newEnd) {
+ fastFree(m_blocks.last());
+ m_blocks.removeLast();
+ }
+}
+
+}
+
+using WTF::BlockStack;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/BloomFilter.h b/Source/JavaScriptCore/wtf/BloomFilter.h
new file mode 100644
index 000000000..f81d83e21
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BloomFilter.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 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 BloomFilter_h
+#define BloomFilter_h
+
+#include <wtf/AlwaysInline.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WTF {
+
+// Counting bloom filter with k=2 and 8 bit counters. Uses 2^keyBits bytes of memory.
+// False positive rate is approximately (1-e^(-2n/m))^2, where n is the number of unique
+// keys and m is the table size (==2^keyBits).
+template <unsigned keyBits>
+class BloomFilter {
+public:
+ COMPILE_ASSERT(keyBits <= 16, bloom_filter_key_size);
+
+ static const size_t tableSize = 1 << keyBits;
+ static const unsigned keyMask = (1 << keyBits) - 1;
+ static uint8_t maximumCount() { return std::numeric_limits<uint8_t>::max(); }
+
+ BloomFilter() { clear(); }
+
+ void add(unsigned hash);
+ void remove(unsigned hash);
+
+ // The filter may give false positives (claim it may contain a key it doesn't)
+ // but never false negatives (claim it doesn't contain a key it does).
+ bool mayContain(unsigned hash) const { return firstSlot(hash) && secondSlot(hash); }
+
+ // The filter must be cleared before reuse even if all keys are removed.
+ // Otherwise overflowed keys will stick around.
+ void clear();
+
+ void add(const AtomicString& string) { add(string.impl()->existingHash()); }
+ void add(const String& string) { add(string.impl()->hash()); }
+ void remove(const AtomicString& string) { remove(string.impl()->existingHash()); }
+ void remove(const String& string) { remove(string.impl()->hash()); }
+
+ bool mayContain(const AtomicString& string) const { return mayContain(string.impl()->existingHash()); }
+ bool mayContain(const String& string) const { return mayContain(string.impl()->hash()); }
+
+#if !ASSERT_DISABLED
+ // Slow.
+ bool likelyEmpty() const;
+ bool isClear() const;
+#endif
+
+private:
+ uint8_t& firstSlot(unsigned hash) { return m_table[hash & keyMask]; }
+ uint8_t& secondSlot(unsigned hash) { return m_table[(hash >> 16) & keyMask]; }
+ const uint8_t& firstSlot(unsigned hash) const { return m_table[hash & keyMask]; }
+ const uint8_t& secondSlot(unsigned hash) const { return m_table[(hash >> 16) & keyMask]; }
+
+ uint8_t m_table[tableSize];
+};
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::add(unsigned hash)
+{
+ uint8_t& first = firstSlot(hash);
+ uint8_t& second = secondSlot(hash);
+ if (LIKELY(first < maximumCount()))
+ ++first;
+ if (LIKELY(second < maximumCount()))
+ ++second;
+}
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::remove(unsigned hash)
+{
+ uint8_t& first = firstSlot(hash);
+ uint8_t& second = secondSlot(hash);
+ ASSERT(first);
+ ASSERT(second);
+ // In case of an overflow, the slot sticks in the table until clear().
+ if (LIKELY(first < maximumCount()))
+ --first;
+ if (LIKELY(second < maximumCount()))
+ --second;
+}
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::clear()
+{
+ memset(m_table, 0, tableSize);
+}
+
+#if !ASSERT_DISABLED
+template <unsigned keyBits>
+bool BloomFilter<keyBits>::likelyEmpty() const
+{
+ for (size_t n = 0; n < tableSize; ++n) {
+ if (m_table[n] && m_table[n] != maximumCount())
+ return false;
+ }
+ return true;
+}
+
+template <unsigned keyBits>
+bool BloomFilter<keyBits>::isClear() const
+{
+ for (size_t n = 0; n < tableSize; ++n) {
+ if (m_table[n])
+ return false;
+ }
+ return true;
+}
+#endif
+
+}
+
+using WTF::BloomFilter;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/BoundsCheckedPointer.h b/Source/JavaScriptCore/wtf/BoundsCheckedPointer.h
new file mode 100644
index 000000000..d5d42fc1c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BoundsCheckedPointer.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2011 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 WTF_BoundsCheckedPointer_h
+#define WTF_BoundsCheckedPointer_h
+
+#include "Assertions.h"
+#include "UnusedParam.h"
+
+namespace WTF {
+
+// Useful for when you'd like to do pointer arithmetic on a buffer, but
+// you'd also like to get some ASSERT()'s that prevent you from overflowing.
+// This should be performance-neutral in release builds, while providing
+// you with strong assertions in debug builds. Note that all of the
+// asserting happens when you actually access the pointer. You are allowed
+// to overflow or underflow with arithmetic so long as no accesses are
+// performed.
+
+template<typename T>
+class BoundsCheckedPointer {
+public:
+ BoundsCheckedPointer()
+ : m_pointer(0)
+#if !ASSERT_DISABLED
+ , m_begin(0)
+ , m_end(0)
+#endif
+ {
+ }
+
+ BoundsCheckedPointer(T* pointer, size_t numElements)
+ : m_pointer(pointer)
+#if !ASSERT_DISABLED
+ , m_begin(pointer)
+ , m_end(pointer + numElements)
+#endif
+ {
+ UNUSED_PARAM(numElements);
+ }
+
+ BoundsCheckedPointer(T* pointer, T* end)
+ : m_pointer(pointer)
+#if !ASSERT_DISABLED
+ , m_begin(pointer)
+ , m_end(end)
+#endif
+ {
+ UNUSED_PARAM(end);
+ }
+
+ BoundsCheckedPointer(T* pointer, T* begin, size_t numElements)
+ : m_pointer(pointer)
+#if !ASSERT_DISABLED
+ , m_begin(begin)
+ , m_end(begin + numElements)
+#endif
+ {
+ UNUSED_PARAM(begin);
+ UNUSED_PARAM(numElements);
+ }
+
+ BoundsCheckedPointer(T* pointer, T* begin, T* end)
+ : m_pointer(pointer)
+#if !ASSERT_DISABLED
+ , m_begin(begin)
+ , m_end(end)
+#endif
+ {
+ UNUSED_PARAM(begin);
+ UNUSED_PARAM(end);
+ }
+
+ BoundsCheckedPointer& operator=(T* value)
+ {
+ m_pointer = value;
+ return *this;
+ }
+
+ BoundsCheckedPointer& operator+=(ptrdiff_t amount)
+ {
+ m_pointer += amount;
+ return *this;
+ }
+
+ BoundsCheckedPointer& operator-=(ptrdiff_t amount)
+ {
+ m_pointer -= amount;
+ return *this;
+ }
+
+ BoundsCheckedPointer operator+(ptrdiff_t amount) const
+ {
+ BoundsCheckedPointer result = *this;
+ result.m_pointer += amount;
+ return result;
+ }
+
+ BoundsCheckedPointer operator-(ptrdiff_t amount) const
+ {
+ BoundsCheckedPointer result = *this;
+ result.m_pointer -= amount;
+ return result;
+ }
+
+ BoundsCheckedPointer operator++() // prefix
+ {
+ m_pointer++;
+ return *this;
+ }
+
+ BoundsCheckedPointer operator--() // prefix
+ {
+ m_pointer--;
+ return *this;
+ }
+
+ BoundsCheckedPointer operator++(int) // postfix
+ {
+ BoundsCheckedPointer result = *this;
+ m_pointer++;
+ return result;
+ }
+
+ BoundsCheckedPointer operator--(int) // postfix
+ {
+ BoundsCheckedPointer result = *this;
+ m_pointer--;
+ return result;
+ }
+
+ bool operator<(T* other) const
+ {
+ return m_pointer < other;
+ }
+
+ bool operator<=(T* other) const
+ {
+ return m_pointer <= other;
+ }
+
+ bool operator>(T* other) const
+ {
+ return m_pointer > other;
+ }
+
+ bool operator>=(T* other) const
+ {
+ return m_pointer >= other;
+ }
+
+ bool operator==(T* other) const
+ {
+ return m_pointer == other;
+ }
+
+ bool operator!=(T* other) const
+ {
+ return m_pointer != other;
+ }
+
+ bool operator<(BoundsCheckedPointer other) const
+ {
+ return m_pointer < other.m_pointer;
+ }
+
+ bool operator<=(BoundsCheckedPointer other) const
+ {
+ return m_pointer <= other.m_pointer;
+ }
+
+ bool operator>(BoundsCheckedPointer other) const
+ {
+ return m_pointer > other.m_pointer;
+ }
+
+ bool operator>=(BoundsCheckedPointer other) const
+ {
+ return m_pointer >= other.m_pointer;
+ }
+
+ bool operator==(BoundsCheckedPointer other) const
+ {
+ return m_pointer == other.m_pointer;
+ }
+
+ bool operator!=(BoundsCheckedPointer other) const
+ {
+ return m_pointer != other.m_pointer;
+ }
+
+ BoundsCheckedPointer operator!()
+ {
+ return !m_pointer;
+ }
+
+ T* get()
+ {
+ return m_pointer;
+ }
+
+ T& operator*()
+ {
+ validate();
+ return *m_pointer;
+ }
+
+ const T& operator*() const
+ {
+ validate();
+ return *m_pointer;
+ }
+
+ T& operator[](ptrdiff_t index)
+ {
+ validate(m_pointer + index);
+ return m_pointer[index];
+ }
+
+ const T& operator[](ptrdiff_t index) const
+ {
+ validate(m_pointer + index);
+ return m_pointer[index];
+ }
+
+ // The only thing this has in common with strcat() is that it
+ // keeps appending from the given pointer until reaching 0.
+ BoundsCheckedPointer& strcat(const T* source)
+ {
+ while (*source)
+ *(*this)++ = *source++;
+ return *this;
+ }
+
+private:
+ void validate(T* pointer) const
+ {
+ ASSERT_UNUSED(pointer, pointer >= m_begin);
+
+ // This guard is designed to protect against the misaligned case.
+ // A simple pointer < m_end would miss the case if, for example,
+ // T = int16_t and pointer is 1 byte less than m_end.
+ ASSERT_UNUSED(pointer, pointer + 1 <= m_end);
+ }
+
+ void validate() const
+ {
+ validate(m_pointer);
+ }
+
+ T* m_pointer;
+#if !ASSERT_DISABLED
+ T* m_begin;
+ T* m_end;
+#endif
+};
+
+} // namespace WTF
+
+using WTF::BoundsCheckedPointer;
+
+#endif // WTF_BoundsCheckedPointer_h
diff --git a/Source/JavaScriptCore/wtf/BumpPointerAllocator.h b/Source/JavaScriptCore/wtf/BumpPointerAllocator.h
new file mode 100644
index 000000000..12911a4b0
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/BumpPointerAllocator.h
@@ -0,0 +1,250 @@
+/*
+ * 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()
+ {
+ m_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/Source/JavaScriptCore/wtf/ByteArray.cpp b/Source/JavaScriptCore/wtf/ByteArray.cpp
new file mode 100644
index 000000000..80c603f30
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ByteArray.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "ByteArray.h"
+
+#include "StdLibExtras.h"
+
+namespace WTF {
+
+PassRefPtr<ByteArray> ByteArray::create(size_t size)
+{
+ unsigned char* buffer = new unsigned char[size + OBJECT_OFFSETOF(ByteArray, m_data)];
+ ASSERT((reinterpret_cast<size_t>(buffer) & 3) == 0);
+ return adoptRef(new (NotNull, buffer) ByteArray(size));
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/ByteArray.h b/Source/JavaScriptCore/wtf/ByteArray.h
new file mode 100644
index 000000000..009ec5850
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ByteArray.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 ByteArray_h
+#define ByteArray_h
+
+#include <limits.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Platform.h>
+#include <wtf/RefCounted.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+ class ByteArray : public RefCountedBase {
+ public:
+ unsigned length() const { return m_size; }
+
+ void set(unsigned index, double value)
+ {
+ if (index >= m_size)
+ return;
+ if (!(value > 0)) // Clamp NaN to 0
+ value = 0;
+ else if (value > 255)
+ value = 255;
+ m_data[index] = static_cast<unsigned char>(value + 0.5);
+ }
+
+ void set(unsigned index, unsigned char value)
+ {
+ if (index >= m_size)
+ return;
+ m_data[index] = value;
+ }
+
+ bool get(unsigned index, unsigned char& result) const
+ {
+ if (index >= m_size)
+ return false;
+ result = m_data[index];
+ return true;
+ }
+
+ unsigned char get(unsigned index) const
+ {
+ ASSERT(index < m_size);
+ return m_data[index];
+ }
+
+ unsigned char* data() { return m_data; }
+
+ void clear() { memset(m_data, 0, m_size); }
+
+ void deref()
+ {
+ if (derefBase()) {
+ // We allocated with new unsigned char[] in create(),
+ // and then used placement new to construct the object.
+ this->~ByteArray();
+ delete[] reinterpret_cast<unsigned char*>(this);
+ }
+ }
+
+ static PassRefPtr<ByteArray> create(size_t size);
+
+ static size_t offsetOfSize() { return OBJECT_OFFSETOF(ByteArray, m_size); }
+ static size_t offsetOfData() { return OBJECT_OFFSETOF(ByteArray, m_data); }
+
+ private:
+ ByteArray(size_t size)
+ : m_size(size)
+ {
+ }
+ size_t m_size;
+// 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) && !COMPILER(INTEL)
+ unsigned char m_data[INT_MAX];
+#else
+ unsigned char m_data[];
+#endif
+ };
+} // namespace WTF
+
+using WTF::ByteArray;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/CMakeLists.txt b/Source/JavaScriptCore/wtf/CMakeLists.txt
new file mode 100644
index 000000000..6d1cee899
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CMakeLists.txt
@@ -0,0 +1,226 @@
+SET(WTF_HEADERS
+ ASCIICType.h
+ AVLTree.h
+ Alignment.h
+ AlwaysInline.h
+ ArrayBuffer.cpp
+ ArrayBufferView.cpp
+ Assertions.h
+ Atomics.h
+ BitVector.h
+ Bitmap.h
+ BoundsCheckedPointer.h
+ BumpPointerAllocator.h
+ ByteArray.h
+ Compiler.h
+ Complex.h
+ CryptographicallyRandomNumber.h
+ CurrentTime.h
+ DateMath.h
+ DecimalNumber.h
+ Decoder.h
+ Deque.h
+ DisallowCType.h
+ DoublyLinkedList.h
+ DynamicAnnotations.h
+ Encoder.h
+ FastAllocBase.h
+ FastMalloc.h
+ FixedArray.h
+ Forward.h
+ GetPtr.h
+ HashCountedSet.h
+ HashFunctions.h
+ HashIterators.h
+ HashMap.h
+ HashSet.h
+ HashTable.h
+ HashTraits.h
+ HexNumber.h
+ ListHashSet.h
+ ListRefPtr.h
+ Locker.h
+ MD5.h
+ MainThread.h
+ MallocZoneSupport.h
+ MathExtras.h
+ MessageQueue.h
+ MetaAllocator.cpp
+ MetaAllocator.h
+ MetaAllocatorHandle.h
+ NonCopyingSort.h
+ ThreadRestrictionVerifier.h
+ Noncopyable.h
+ NotFound.h
+ NullPtr.h
+ OSAllocator.h
+ OSRandomSource.h
+ OwnArrayPtr.h
+ OwnFastMallocPtr.h
+ OwnPtr.h
+ OwnPtrCommon.h
+ PageAllocation.h
+ PageAllocationAligned.h
+ PageBlock.h
+ PageReservation.h
+ PassOwnArrayPtr.h
+ PassOwnPtr.h
+ PassRefPtr.h
+ PassTraits.h
+ ParallelJobs.h
+ ParallelJobsGeneric.h
+ ParallelJobsLibdispatch.h
+ ParallelJobsOpenMP.h
+ Platform.h
+ PossiblyNull.h
+ RandomNumber.h
+ RandomNumberSeed.h
+ RedBlackTree.h
+ RefCounted.h
+ RefCountedLeakCounter.h
+ RefPtr.h
+ RefPtrHashMap.h
+ RetainPtr.h
+ SegmentedVector.h
+ SHA1.h
+ StackBounds.h
+ StaticConstructors.h
+ StdLibExtras.h
+ StringExtras.h
+ StringHasher.h
+ TCPackedCache.h
+ TCPageMap.h
+ TCSpinLock.h
+ TCSystemAlloc.h
+ ThreadIdentifierDataPthreads.h
+ ThreadSafeRefCounted.h
+ ThreadSpecific.h
+ Threading.h
+ ThreadingPrimitives.h
+ TypeTraits.h
+ UnusedParam.h
+ VMTags.h
+ ValueCheck.h
+ Vector.h
+ VectorTraits.h
+ WTFThreadData.h
+ dtoa.h
+
+ dtoa/bignum-dtoa.h
+ dtoa/bignum.h
+ dtoa/cached-powers.h
+ dtoa/diy-fp.h
+ dtoa/double-conversion.h
+ dtoa/double.h
+ dtoa/fast-dtoa.h
+ dtoa/fixed-dtoa.h
+ dtoa/strtod.h
+ dtoa/utils.h
+
+ text/AtomicString.h
+ text/AtomicStringImpl.h
+ text/CString.h
+ text/StringBuffer.h
+ text/StringHash.h
+ text/StringImpl.h
+ text/WTFString.h
+
+ threads/BinarySemaphore.h
+
+ unicode/CharacterNames.h
+ unicode/Collator.h
+ unicode/UTF8.h
+ unicode/Unicode.h
+)
+
+SET(WTF_SOURCES
+ Assertions.cpp
+ BitVector.cpp
+ ByteArray.cpp
+ CryptographicallyRandomNumber.cpp
+ CurrentTime.cpp
+ DateMath.cpp
+ DecimalNumber.cpp
+ DynamicAnnotations.cpp
+ FastMalloc.cpp
+ HashTable.cpp
+ MainThread.cpp
+ MD5.cpp
+ OSRandomSource.cpp
+ PageAllocationAligned.cpp
+ PageBlock.cpp
+ ParallelJobsGeneric.cpp
+ RandomNumber.cpp
+ RefCountedLeakCounter.cpp
+ SHA1.cpp
+ StackBounds.cpp
+ StringExtras.cpp
+ Threading.cpp
+ TypeTraits.cpp
+ WTFThreadData.cpp
+ dtoa.cpp
+
+ dtoa/bignum-dtoa.cc
+ dtoa/bignum.cc
+ dtoa/cached-powers.cc
+ dtoa/diy-fp.cc
+ dtoa/double-conversion.cc
+ dtoa/fast-dtoa.cc
+ dtoa/fixed-dtoa.cc
+ dtoa/strtod.cc
+
+ text/AtomicString.cpp
+ text/CString.cpp
+ text/StringBuilder.cpp
+ text/StringImpl.cpp
+ text/StringStatics.cpp
+ text/WTFString.cpp
+
+ threads/BinarySemaphore.cpp
+
+ unicode/UTF8.cpp
+)
+
+SET(WTF_INCLUDE_DIRECTORIES
+ "${JAVASCRIPTCORE_DIR}"
+ "${JAVASCRIPTCORE_DIR}/wtf"
+ "${JAVASCRIPTCORE_DIR}/wtf/unicode"
+ "${JAVASCRIPTCORE_DIR}/wtf/dtoa"
+ "${JavaScriptCore_INCLUDE_DIRECTORIES}"
+)
+
+SET(WTF_LIBRARIES
+)
+
+
+IF (ENABLE_FAST_MALLOC)
+ LIST(APPEND WTF_SOURCES
+ TCSystemAlloc.cpp
+ )
+ELSE ()
+ ADD_DEFINITIONS(-DUSE_SYSTEM_MALLOC=1)
+ENDIF()
+
+
+SET(WTF_PORT_FLAGS )
+INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/wtf/Platform${PORT}.cmake)
+
+LIST(APPEND WTF_INCLUDE_DIRECTORIES
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_SOURCE_DIR}/Source/ThirdParty"
+)
+
+WEBKIT_WRAP_SOURCELIST(${WTF_SOURCES})
+INCLUDE_DIRECTORIES(${WTF_INCLUDE_DIRECTORIES})
+ADD_DEFINITIONS(-DBUILDING_WTF)
+ADD_LIBRARY(${WTF_LIBRARY_NAME} ${WTF_LIBRARY_TYPE} ${WTF_HEADERS} ${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/Source/JavaScriptCore/wtf/CONTRIBUTORS.pthreads-win32 b/Source/JavaScriptCore/wtf/CONTRIBUTORS.pthreads-win32
new file mode 100644
index 000000000..7de0f2606
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CONTRIBUTORS.pthreads-win32
@@ -0,0 +1,137 @@
+This is a copy of CONTRIBUTORS file for the Pthreads-win32 library, downloaded
+from http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/pthreads/CONTRIBUTORS?rev=1.32&cvsroot=pthreads-win32
+
+Included here to compliment the Pthreads-win32 license header in wtf/ThreadingWin.cpp file.
+WebKit is using derived sources of ThreadCondition code from Pthreads-win32.
+
+-------------------------------------------------------------------------------
+
+Contributors (in approximate order of appearance)
+
+[See also the ChangeLog file where individuals are
+attributed in log entries. Likewise in the FAQ file.]
+
+Ben Elliston bje at cygnus dot com
+ Initiated the project;
+ setup the project infrastructure (CVS, web page, etc.);
+ early prototype routines.
+Ross Johnson rpj at callisto dot canberra dot edu dot au
+ early prototype routines;
+ ongoing project coordination/maintenance;
+ implementation of spin locks and barriers;
+ various enhancements;
+ bug fixes;
+ documentation;
+ testsuite.
+Robert Colquhoun rjc at trump dot net dot au
+ Early bug fixes.
+John E. Bossom John dot Bossom at cognos dot com
+ Contributed substantial original working implementation;
+ bug fixes;
+ ongoing guidance and standards interpretation.
+Anders Norlander anorland at hem2 dot passagen dot se
+ Early enhancements and runtime checking for supported
+ Win32 routines.
+Tor Lillqvist tml at iki dot fi
+ General enhancements;
+ early bug fixes to condition variables.
+Scott Lightner scott at curriculum dot com
+ Bug fix.
+Kevin Ruland Kevin dot Ruland at anheuser-busch dot com
+ Various bug fixes.
+Mike Russo miker at eai dot com
+ Bug fix.
+Mark E. Armstrong avail at pacbell dot net
+ Bug fixes.
+Lorin Hochstein lmh at xiphos dot ca
+ general bug fixes; bug fixes to condition variables.
+Peter Slacik Peter dot Slacik at tatramed dot sk
+ Bug fixes.
+Mumit Khan khan at xraylith dot wisc dot edu
+ Fixes to work with Mingw32.
+Milan Gardian mg at tatramed dot sk
+ Bug fixes and reports/analyses of obscure problems.
+Aurelio Medina aureliom at crt dot com
+ First implementation of read-write locks.
+Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au
+ Bug fix in condition variables.
+Tristan Savatier tristan at mpegtv dot com
+ WinCE port.
+Erik Hensema erik at hensema dot xs4all dot nl
+ Bug fixes.
+Rich Peters rpeters at micro-magic dot com
+Todd Owen towen at lucidcalm dot dropbear dot id dot au
+ Bug fixes to dll loading.
+Jason Nye jnye at nbnet dot nb dot ca
+ Implementation of async cancelation.
+Fred Forester fforest at eticomm dot net
+Kevin D. Clark kclark at cabletron dot com
+David Baggett dmb at itasoftware dot com
+ Bug fixes.
+Paul Redondo paul at matchvision dot com
+Scott McCaskill scott at 3dfx dot com
+ Bug fixes.
+Jef Gearhart jgearhart at tpssys dot com
+ Bug fix.
+Arthur Kantor akantor at bexusa dot com
+ Mutex enhancements.
+Steven Reddie smr at essemer dot com dot au
+ Bug fix.
+Alexander Terekhov TEREKHOV at de dot ibm dot com
+ Re-implemented and improved read-write locks;
+ (with Louis Thomas) re-implemented and improved
+ condition variables;
+ enhancements to semaphores;
+ enhancements to mutexes;
+ new mutex implementation in 'futex' style;
+ suggested a robust implementation of pthread_once
+ similar to that implemented by V.Kliathcko;
+ system clock change handling re CV timeouts;
+ bug fixes.
+Thomas Pfaff tpfaff at gmx dot net
+ Changes to make C version usable with C++ applications;
+ re-implemented mutex routines to avoid Win32 mutexes
+ and TryEnterCriticalSection;
+ procedure to fix Mingw32 thread-safety issues.
+Franco Bez franco dot bez at gmx dot de
+ procedure to fix Mingw32 thread-safety issues.
+Louis Thomas lthomas at arbitrade dot com
+ (with Alexander Terekhov) re-implemented and improved
+ condition variables.
+David Korn dgk at research dot att dot com
+ Ported to UWIN.
+Phil Frisbie, Jr. phil at hawksoft dot com
+ Bug fix.
+Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de
+ Bug fix.
+prionx at juno dot com prionx at juno dot com
+ Bug fixes.
+Max Woodbury mtew at cds dot duke dot edu
+ POSIX versioning conditionals;
+ reduced namespace pollution;
+ idea to separate routines to reduce statically
+ linked image sizes.
+Rob Fanner rfanner at stonethree dot com
+ Bug fix.
+Michael Johnson michaelj at maine dot rr dot com
+ Bug fix.
+Nicolas Barry boozai at yahoo dot com
+ Bug fixes.
+Piet van Bruggen pietvb at newbridges dot nl
+ Bug fix.
+Makoto Kato raven at oldskool dot jp
+ AMD64 port.
+Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr
+ Contributed the QueueUserAPCEx package which
+ makes preemptive async cancelation possible.
+Will Bryant will dot bryant at ecosm dot com
+ Borland compiler patch and makefile.
+Anuj Goyal anuj dot goyal at gmail dot com
+ Port to Digital Mars compiler.
+Gottlob Frege gottlobfrege at gmail dot com
+ re-implemented pthread_once (version 2)
+ (pthread_once cancellation added by rpj).
+Vladimir Kliatchko vladimir at kliatchko dot com
+ reimplemented pthread_once with the same form
+ as described by A.Terekhov (later version 2);
+ implementation of MCS (Mellor-Crummey/Scott) locks. \ No newline at end of file
diff --git a/Source/JavaScriptCore/wtf/CheckedArithmetic.h b/Source/JavaScriptCore/wtf/CheckedArithmetic.h
new file mode 100644
index 000000000..f90efae41
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CheckedArithmetic.h
@@ -0,0 +1,693 @@
+/*
+ * Copyright (C) 2011 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 CheckedArithmetic_h
+#define CheckedArithmetic_h
+
+#include "Assertions.h"
+#include "TypeTraits.h"
+
+#include <limits>
+#include <stdint.h>
+
+/* Checked<T>
+ *
+ * This class provides a mechanism to perform overflow-safe integer arithmetic
+ * without having to manually ensure that you have all the required bounds checks
+ * directly in your code.
+ *
+ * There are two modes of operation:
+ * - The default is Checked<T, CrashOnOverflow>, and crashes at the point
+ * and overflow has occurred.
+ * - The alternative is Checked<T, RecordOverflow>, which uses an additional
+ * byte of storage to track whether an overflow has occurred, subsequent
+ * unchecked operations will crash if an overflow has occured
+ *
+ * It is possible to provide a custom overflow handler, in which case you need
+ * to support these functions:
+ * - void overflowed();
+ * This function is called when an operation has produced an overflow.
+ * - bool hasOverflowed();
+ * This function must return true if overflowed() has been called on an
+ * instance and false if it has not.
+ * - void clearOverflow();
+ * Used to reset overflow tracking when a value is being overwritten with
+ * a new value.
+ *
+ * Checked<T> works for all integer types, with the following caveats:
+ * - Mixing signedness of operands is only supported for types narrower than
+ * 64bits.
+ * - It does have a performance impact, so tight loops may want to be careful
+ * when using it.
+ *
+ */
+
+namespace WTF {
+
+class CrashOnOverflow {
+protected:
+ NO_RETURN_DUE_TO_CRASH void overflowed()
+ {
+ CRASH();
+ }
+
+ void clearOverflow() { }
+
+public:
+ bool hasOverflowed() const { return false; }
+};
+
+class RecordOverflow {
+protected:
+ RecordOverflow()
+ : m_overflowed(false)
+ {
+ }
+
+ void overflowed()
+ {
+ m_overflowed = true;
+ }
+
+ void clearOverflow()
+ {
+ m_overflowed = false;
+ }
+
+public:
+ bool hasOverflowed() const { return m_overflowed; }
+
+private:
+ unsigned char m_overflowed;
+};
+
+template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
+template <typename T> struct RemoveChecked;
+template <typename T> struct RemoveChecked<Checked<T> >;
+
+template <typename Target, typename Source, bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker;
+template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
+ static bool inBounds(Source value)
+ {
+ // Same signedness so implicit type conversion will always increase precision
+ // to widest type
+ return value <= std::numeric_limits<Target>::max();
+ }
+};
+
+template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
+ static bool inBounds(Source value)
+ {
+ // Same signedness so implicit type conversion will always increase precision
+ // to widest type
+ return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max();
+ }
+};
+
+template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
+ static bool inBounds(Source value)
+ {
+ // Target is unsigned so any value less than zero is clearly unsafe
+ if (value < 0)
+ return false;
+ // If our (unsigned) Target is the same or greater width we can
+ // convert value to type Target without losing precision
+ if (sizeof(Target) >= sizeof(Source))
+ return static_cast<Target>(value) <= std::numeric_limits<Target>::max();
+ // The signed Source type has greater precision than the target so
+ // max(Target) -> Source will widen.
+ return value <= static_cast<Source>(std::numeric_limits<Target>::max());
+ }
+};
+
+template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
+ static bool inBounds(Source value)
+ {
+ // Signed target with an unsigned source
+ if (sizeof(Target) <= sizeof(Source))
+ return value <= static_cast<Source>(std::numeric_limits<Target>::max());
+ // Target is Wider than Source so we're guaranteed to fit any value in
+ // unsigned Source
+ return true;
+ }
+};
+
+template <typename Target, typename Source, bool SameType = IsSameType<Target, Source>::value> struct BoundsCheckElider;
+template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
+ static bool inBounds(Source) { return true; }
+};
+template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
+};
+
+template <typename Target, typename Source> static inline bool isInBounds(Source value)
+{
+ return BoundsCheckElider<Target, Source>::inBounds(value);
+}
+
+template <typename T> struct RemoveChecked {
+ typedef T CleanType;
+ static const CleanType DefaultValue = 0;
+};
+
+template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
+ typedef typename RemoveChecked<T>::CleanType CleanType;
+ static const CleanType DefaultValue = 0;
+};
+
+template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
+ typedef typename RemoveChecked<T>::CleanType CleanType;
+ static const CleanType DefaultValue = 0;
+};
+
+// The ResultBase and SignednessSelector are used to workaround typeof not being
+// available in MSVC
+template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
+template <typename U, typename V> struct ResultBase<U, V, true, false> {
+ typedef U ResultType;
+};
+
+template <typename U, typename V> struct ResultBase<U, V, false, false> {
+ typedef V ResultType;
+};
+
+template <typename U> struct ResultBase<U, U, false, true> {
+ typedef U ResultType;
+};
+
+template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector;
+template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
+ typedef U ResultType;
+};
+
+template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
+ typedef U ResultType;
+};
+
+template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
+ typedef V ResultType;
+};
+
+template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
+ typedef U ResultType;
+};
+
+template <typename U, typename V> struct ResultBase<U, V, false, true> {
+ typedef typename SignednessSelector<U, V>::ResultType ResultType;
+};
+
+template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
+};
+
+template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
+ bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
+
+template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
+ // LHS and RHS are signed types
+
+ // Helper function
+ static inline bool signsMatch(LHS lhs, RHS rhs)
+ {
+ return (lhs ^ rhs) >= 0;
+ }
+
+ static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ if (signsMatch(lhs, rhs)) {
+ if (lhs >= 0) {
+ if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
+ return false;
+ } else {
+ ResultType temp = lhs - std::numeric_limits<ResultType>::min();
+ if (rhs < -temp)
+ return false;
+ }
+ } // if the signs do not match this operation can't overflow
+ result = lhs + rhs;
+ return true;
+ }
+
+ static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ if (!signsMatch(lhs, rhs)) {
+ if (lhs >= 0) {
+ if (lhs > std::numeric_limits<ResultType>::max() + rhs)
+ return false;
+ } else {
+ if (rhs > std::numeric_limits<ResultType>::max() + lhs)
+ return false;
+ }
+ } // if the signs match this operation can't overflow
+ result = lhs - rhs;
+ return true;
+ }
+
+ static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ if (signsMatch(lhs, rhs)) {
+ if (lhs >= 0) {
+ if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
+ return false;
+ } else {
+ if (lhs == std::numeric_limits<ResultType>::min() || rhs == std::numeric_limits<ResultType>::min())
+ return false;
+ if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
+ return false;
+ }
+ } else {
+ if (lhs < 0) {
+ if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
+ return false;
+ } else {
+ if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
+ return false;
+ }
+ }
+ result = lhs * rhs;
+ return true;
+ }
+
+ static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
+
+};
+
+template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
+ // LHS and RHS are unsigned types so bounds checks are nice and easy
+ static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ ResultType temp = lhs + rhs;
+ if (temp < lhs)
+ return false;
+ result = temp;
+ return true;
+ }
+
+ static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ ResultType temp = lhs - rhs;
+ if (temp > lhs)
+ return false;
+ result = temp;
+ return true;
+ }
+
+ static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
+ {
+ ResultType temp = lhs * rhs;
+ if (temp < lhs)
+ return false;
+ result = temp;
+ return true;
+ }
+
+ static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
+
+};
+
+template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
+ static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ int64_t temp = lhs + rhs;
+ if (temp < std::numeric_limits<ResultType>::min())
+ return false;
+ if (temp > std::numeric_limits<ResultType>::max())
+ return false;
+ result = static_cast<ResultType>(temp);
+ return true;
+ }
+
+ static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ int64_t temp = lhs - rhs;
+ if (temp < std::numeric_limits<ResultType>::min())
+ return false;
+ if (temp > std::numeric_limits<ResultType>::max())
+ return false;
+ result = static_cast<ResultType>(temp);
+ return true;
+ }
+
+ static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ int64_t temp = lhs * rhs;
+ if (temp < std::numeric_limits<ResultType>::min())
+ return false;
+ if (temp > std::numeric_limits<ResultType>::max())
+ return false;
+ result = static_cast<ResultType>(temp);
+ return true;
+ }
+
+ static inline bool equals(int lhs, unsigned rhs)
+ {
+ return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
+ }
+};
+
+template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
+ static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
+ }
+
+ static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
+ }
+
+ static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
+ {
+ return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
+ }
+
+ static inline bool equals(unsigned lhs, int rhs)
+ {
+ return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
+ }
+};
+
+template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
+{
+ return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
+}
+
+template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
+{
+ return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
+}
+
+template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
+{
+ return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
+}
+
+template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
+{
+ return ArithmeticOperations<U, V>::equals(lhs, rhs);
+}
+
+enum ResultOverflowedTag { ResultOverflowed };
+
+// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801
+static inline bool workAroundClangBug() { return true; }
+
+template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
+public:
+ template <typename _T, class _OverflowHandler> friend class Checked;
+ Checked()
+ : m_value(0)
+ {
+ }
+
+ Checked(ResultOverflowedTag)
+ : m_value(0)
+ {
+ // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
+ if (workAroundClangBug())
+ this->overflowed();
+ }
+
+ template <typename U> Checked(U value)
+ {
+ if (!isInBounds<T>(value))
+ this->overflowed();
+ m_value = static_cast<T>(value);
+ }
+
+ template <typename V> Checked(const Checked<T, V>& rhs)
+ : m_value(rhs.m_value)
+ {
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ }
+
+ template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
+ : OverflowHandler(rhs)
+ {
+ if (!isInBounds<T>(rhs.m_value))
+ this->overflowed();
+ m_value = static_cast<T>(rhs.m_value);
+ }
+
+ template <typename U, typename V> Checked(const Checked<U, V>& rhs)
+ {
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ if (!isInBounds<T>(rhs.m_value))
+ this->overflowed();
+ m_value = static_cast<T>(rhs.m_value);
+ }
+
+ const Checked& operator=(Checked rhs)
+ {
+ this->clearOverflow();
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ m_value = static_cast<T>(rhs.m_value);
+ return *this;
+ }
+
+ template <typename U> const Checked& operator=(U value)
+ {
+ return *this = Checked(value);
+ }
+
+ template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
+ {
+ return *this = Checked(rhs);
+ }
+
+ // prefix
+ const Checked& operator++()
+ {
+ if (m_value == std::numeric_limits<T>::max())
+ this->overflowed();
+ m_value++;
+ return *this;
+ }
+
+ const Checked& operator--()
+ {
+ if (m_value == std::numeric_limits<T>::min())
+ this->overflowed();
+ m_value--;
+ return *this;
+ }
+
+ // postfix operators
+ const Checked operator++(int)
+ {
+ if (m_value == std::numeric_limits<T>::max())
+ this->overflowed();
+ return Checked(m_value++);
+ }
+
+ const Checked operator--(int)
+ {
+ if (m_value == std::numeric_limits<T>::min())
+ this->overflowed();
+ return Checked(m_value--);
+ }
+
+ // Boolean operators
+ bool operator!() const
+ {
+ if (this->hasOverflowed())
+ CRASH();
+ return !m_value;
+ }
+
+ typedef void* (Checked::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const
+ {
+ if (this->hasOverflowed())
+ CRASH();
+ return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
+ }
+
+ // Value accessors. unsafeGet() will crash if there's been an overflow.
+ T unsafeGet() const
+ {
+ if (this->hasOverflowed())
+ CRASH();
+ return m_value;
+ }
+
+ bool safeGet(T& value) const WARN_UNUSED_RETURN
+ {
+ value = m_value;
+ return this->hasOverflowed();
+ }
+
+ // Mutating assignment
+ template <typename U> const Checked operator+=(U rhs)
+ {
+ if (!safeAdd(m_value, rhs, m_value))
+ this->overflowed();
+ return *this;
+ }
+
+ template <typename U> const Checked operator-=(U rhs)
+ {
+ if (!safeSub(m_value, rhs, m_value))
+ this->overflowed();
+ return *this;
+ }
+
+ template <typename U> const Checked operator*=(U rhs)
+ {
+ if (!safeMultiply(m_value, rhs, m_value))
+ this->overflowed();
+ return *this;
+ }
+
+ template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
+ {
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ return *this += rhs.m_value;
+ }
+
+ template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
+ {
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ return *this -= rhs.m_value;
+ }
+
+ template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
+ {
+ if (rhs.hasOverflowed())
+ this->overflowed();
+ return *this *= rhs.m_value;
+ }
+
+ // Equality comparisons
+ template <typename V> bool operator==(Checked<T, V> rhs)
+ {
+ return unsafeGet() == rhs.unsafeGet();
+ }
+
+ template <typename U> bool operator==(U rhs)
+ {
+ if (this->hasOverflowed())
+ this->overflowed();
+ return safeEquals(m_value, rhs);
+ }
+
+ template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
+ {
+ return unsafeGet() == Checked(rhs.unsafeGet());
+ }
+
+ template <typename U> bool operator!=(U rhs)
+ {
+ return !(*this == rhs);
+ }
+
+private:
+ // Disallow implicit conversion of floating point to integer types
+ Checked(float);
+ Checked(double);
+ void operator=(float);
+ void operator=(double);
+ void operator+=(float);
+ void operator+=(double);
+ void operator-=(float);
+ void operator-=(double);
+ T m_value;
+};
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
+{
+ U x = 0;
+ V y = 0;
+ bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
+ typename Result<U, V>::ResultType result = 0;
+ overflowed |= !safeAdd(x, y, result);
+ if (overflowed)
+ return ResultOverflowed;
+ return result;
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
+{
+ U x = 0;
+ V y = 0;
+ bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
+ typename Result<U, V>::ResultType result = 0;
+ overflowed |= !safeSub(x, y, result);
+ if (overflowed)
+ return ResultOverflowed;
+ return result;
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
+{
+ U x = 0;
+ V y = 0;
+ bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
+ typename Result<U, V>::ResultType result = 0;
+ overflowed |= !safeMultiply(x, y, result);
+ if (overflowed)
+ return ResultOverflowed;
+ return result;
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
+{
+ return lhs + Checked<V, OverflowHandler>(rhs);
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
+{
+ return lhs - Checked<V, OverflowHandler>(rhs);
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
+{
+ return lhs * Checked<V, OverflowHandler>(rhs);
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
+{
+ return Checked<U, OverflowHandler>(lhs) + rhs;
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
+{
+ return Checked<U, OverflowHandler>(lhs) - rhs;
+}
+
+template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
+{
+ return Checked<U, OverflowHandler>(lhs) * rhs;
+}
+
+}
+
+using WTF::Checked;
+using WTF::RecordOverflow;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/Compiler.h b/Source/JavaScriptCore/wtf/Compiler.h
new file mode 100644
index 000000000..93d3316bf
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Compiler.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 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_Compiler_h
+#define WTF_Compiler_h
+
+/* COMPILER() - the compiler being used to build the project */
+#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE)
+
+/* COMPILER_SUPPORTS() - whether the compiler being used to build the project supports the given feature. */
+#define COMPILER_SUPPORTS(WTF_COMPILER_FEATURE) (defined WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE && WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE)
+
+/* ==== COMPILER() - the compiler being used to build the project ==== */
+
+/* COMPILER(CLANG) - Clang */
+#if defined(__clang__)
+#define WTF_COMPILER_CLANG 1
+
+#ifndef __has_extension
+#define __has_extension __has_feature /* Compatibility with older versions of clang */
+#endif
+
+/* Specific compiler features */
+#define WTF_COMPILER_SUPPORTS_CXX_VARIADIC_TEMPLATES __has_feature(cxx_variadic_templates)
+#define WTF_COMPILER_SUPPORTS_CXX_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
+#define WTF_COMPILER_SUPPORTS_CXX_DELETED_FUNCTIONS __has_feature(cxx_deleted_functions)
+#define WTF_COMPILER_SUPPORTS_CXX_NULLPTR __has_feature(cxx_nullptr)
+#define WTF_COMPILER_SUPPORTS_BLOCKS __has_feature(blocks)
+
+#endif
+
+/* COMPILER(MSVC) - Microsoft Visual C++ */
+/* 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_OR_LOWER 1
+#elif _MSC_VER < 1600
+#define WTF_COMPILER_MSVC9_OR_LOWER 1
+#endif
+
+/* Specific compiler features */
+#if _MSC_VER >= 1600
+#define WTF_COMPILER_SUPPORTS_CXX_NULLPTR 1
+#endif
+
+#endif
+
+/* COMPILER(RVCT) - ARM RealView Compilation Tools */
+/* COMPILER(RVCT4_OR_GREATER) - ARM RealView Compilation Tools 4.0 or greater */
+#if defined(__CC_ARM) || defined(__ARMCC__)
+#define WTF_COMPILER_RVCT 1
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
+#else
+/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
+#endif
+
+/* COMPILER(GCCE) - GNU Compiler Collection for Embedded */
+#if defined(__GCCE__)
+#define WTF_COMPILER_GCCE 1
+#define GCCE_VERSION (__GCCE__ * 10000 + __GCCE_MINOR__ * 100 + __GCCE_PATCHLEVEL__)
+#define GCCE_VERSION_AT_LEAST(major, minor, patch) (GCCE_VERSION >= (major * 10000 + minor * 100 + patch))
+#endif
+
+/* COMPILER(GCC) - GNU Compiler Collection */
+/* --gnu option of the RVCT compiler also defines __GNUC__ */
+#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))
+
+/* Specific compiler features */
+#if !COMPILER(CLANG) && GCC_VERSION_AT_LEAST(4, 6, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define WTF_COMPILER_SUPPORTS_CXX_NULLPTR 1
+#endif
+
+#else
+/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
+#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
+#endif
+
+/* COMPILER(MINGW) - MinGW GCC */
+/* COMPILER(MINGW64) - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
+#if defined(__MINGW32__)
+#define WTF_COMPILER_MINGW 1
+#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(INTEL) - Intel C++ Compiler */
+#if defined(__INTEL_COMPILER)
+#define WTF_COMPILER_INTEL 1
+#endif
+
+/* COMPILER(SUNCC) */
+#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
+#define WTF_COMPILER_SUNCC 1
+#endif
+
+/* ==== Compiler features ==== */
+
+
+/* ALWAYS_INLINE */
+
+#ifndef ALWAYS_INLINE
+#if COMPILER(GCC) && defined(NDEBUG) && !COMPILER(MINGW)
+#define ALWAYS_INLINE inline __attribute__((__always_inline__))
+#elif (COMPILER(MSVC) || COMPILER(RVCT)) && defined(NDEBUG)
+#define ALWAYS_INLINE __forceinline
+#else
+#define ALWAYS_INLINE inline
+#endif
+#endif
+
+
+/* NEVER_INLINE */
+
+#ifndef NEVER_INLINE
+#if COMPILER(GCC)
+#define NEVER_INLINE __attribute__((__noinline__))
+#elif COMPILER(RVCT)
+#define NEVER_INLINE __declspec(noinline)
+#else
+#define NEVER_INLINE
+#endif
+#endif
+
+
+/* UNLIKELY */
+
+#ifndef UNLIKELY
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(3, 0, 0, 0) && defined(__GNUC__))
+#define UNLIKELY(x) __builtin_expect((x), 0)
+#else
+#define UNLIKELY(x) (x)
+#endif
+#endif
+
+
+/* LIKELY */
+
+#ifndef LIKELY
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(3, 0, 0, 0) && defined(__GNUC__))
+#define LIKELY(x) __builtin_expect((x), 1)
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+
+/* NO_RETURN */
+
+
+#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
+
+
+/* NO_RETURN_WITH_VALUE */
+
+#ifndef NO_RETURN_WITH_VALUE
+#if !COMPILER(MSVC)
+#define NO_RETURN_WITH_VALUE NO_RETURN
+#else
+#define NO_RETURN_WITH_VALUE
+#endif
+#endif
+
+
+/* WARN_UNUSED_RETURN */
+
+#if COMPILER(GCC)
+#define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
+#else
+#define WARN_UNUSED_RETURN
+#endif
+
+/* OVERRIDE */
+
+#ifndef OVERRIDE
+#if COMPILER(CLANG)
+#if __has_extension(cxx_override_control)
+#define OVERRIDE override
+#endif
+#elif COMPILER(MSVC)
+#define OVERRIDE override
+#endif
+#endif
+
+#ifndef OVERRIDE
+#define OVERRIDE
+#endif
+
+/* FINAL */
+
+#ifndef FINAL
+#if COMPILER(CLANG)
+#if __has_extension(cxx_override_control)
+#define FINAL final
+#endif
+#elif COMPILER(MSVC)
+#define FINAL sealed
+#endif
+#endif
+
+#ifndef FINAL
+#define FINAL
+#endif
+
+#endif /* WTF_Compiler_h */
diff --git a/Source/JavaScriptCore/wtf/Complex.h b/Source/JavaScriptCore/wtf/Complex.h
new file mode 100644
index 000000000..40fe56a7b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Complex.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ * 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 WTF_Complex_h
+#define WTF_Complex_h
+
+#include <complex>
+#include <wtf/MathExtras.h>
+
+namespace WTF {
+
+typedef std::complex<double> Complex;
+
+inline Complex complexFromMagnitudePhase(double magnitude, double phase)
+{
+ return Complex(magnitude * cos(phase), magnitude * sin(phase));
+}
+
+} // namespace WTF
+
+using WTF::Complex;
+using WTF::complexFromMagnitudePhase;
+
+#endif // WTF_Complex_h
diff --git a/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp
new file mode 100644
index 000000000..8c16f5314
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include "config.h"
+#include "CryptographicallyRandomNumber.h"
+
+#include "OSRandomSource.h"
+#include "StdLibExtras.h"
+#include "ThreadingPrimitives.h"
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+
+namespace {
+
+class ARC4Stream {
+public:
+ ARC4Stream();
+
+ uint8_t i;
+ uint8_t j;
+ uint8_t s[256];
+};
+
+class ARC4RandomNumberGenerator {
+public:
+ ARC4RandomNumberGenerator();
+
+ uint32_t randomNumber();
+ void randomValues(void* buffer, size_t length);
+
+private:
+ inline void addRandomData(unsigned char *data, int length);
+ void stir();
+ void stirIfNeeded();
+ inline uint8_t getByte();
+ inline uint32_t getWord();
+
+ ARC4Stream m_stream;
+ int m_count;
+ Mutex m_mutex;
+};
+
+ARC4Stream::ARC4Stream()
+{
+ for (int n = 0; n < 256; n++)
+ s[n] = n;
+ i = 0;
+ j = 0;
+}
+
+ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
+ : m_count(0)
+{
+}
+
+void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
+{
+ m_stream.i--;
+ for (int n = 0; n < 256; n++) {
+ m_stream.i++;
+ uint8_t si = m_stream.s[m_stream.i];
+ m_stream.j += si + data[n % length];
+ m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
+ m_stream.s[m_stream.j] = si;
+ }
+ m_stream.j = m_stream.i;
+}
+
+void ARC4RandomNumberGenerator::stir()
+{
+ unsigned char randomness[128];
+ size_t length = sizeof(randomness);
+ cryptographicallyRandomValuesFromOS(randomness, length);
+ addRandomData(randomness, length);
+
+ // Discard early keystream, as per recommendations in:
+ // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ for (int i = 0; i < 256; i++)
+ getByte();
+ m_count = 1600000;
+}
+
+void ARC4RandomNumberGenerator::stirIfNeeded()
+{
+ if (m_count <= 0)
+ stir();
+}
+
+uint8_t ARC4RandomNumberGenerator::getByte()
+{
+ m_stream.i++;
+ uint8_t si = m_stream.s[m_stream.i];
+ m_stream.j += si;
+ uint8_t sj = m_stream.s[m_stream.j];
+ m_stream.s[m_stream.i] = sj;
+ m_stream.s[m_stream.j] = si;
+ return (m_stream.s[(si + sj) & 0xff]);
+}
+
+uint32_t ARC4RandomNumberGenerator::getWord()
+{
+ uint32_t val;
+ val = getByte() << 24;
+ val |= getByte() << 16;
+ val |= getByte() << 8;
+ val |= getByte();
+ return val;
+}
+
+uint32_t ARC4RandomNumberGenerator::randomNumber()
+{
+ MutexLocker locker(m_mutex);
+
+ m_count -= 4;
+ stirIfNeeded();
+ return getWord();
+}
+
+void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
+{
+ MutexLocker locker(m_mutex);
+
+ unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
+ stirIfNeeded();
+ while (length--) {
+ m_count--;
+ stirIfNeeded();
+ result[length] = getByte();
+ }
+}
+
+ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
+{
+ DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ());
+ return randomNumberGenerator;
+}
+
+}
+
+uint32_t cryptographicallyRandomNumber()
+{
+ return sharedRandomNumberGenerator().randomNumber();
+}
+
+void cryptographicallyRandomValues(void* buffer, size_t length)
+{
+ sharedRandomNumberGenerator().randomValues(buffer, length);
+}
+
+#endif
+
+}
diff --git a/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h
new file mode 100644
index 000000000..348242e25
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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.
+ *
+ * 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_CryptographicallyRandomNumber_h
+#define WTF_CryptographicallyRandomNumber_h
+
+#include <stdint.h>
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+uint32_t cryptographicallyRandomNumber();
+void cryptographicallyRandomValues(void* buffer, size_t length);
+#endif
+
+}
+
+#if USE(OS_RANDOMNESS)
+using WTF::cryptographicallyRandomNumber;
+using WTF::cryptographicallyRandomValues;
+#endif
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/CurrentTime.cpp b/Source/JavaScriptCore/wtf/CurrentTime.cpp
new file mode 100644
index 000000000..c8c77f54f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CurrentTime.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * 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 "CurrentTime.h"
+
+#if PLATFORM(MAC)
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#elif OS(WINDOWS)
+
+// Windows is first since we want to use hires timers, despite USE(CF)
+// being defined.
+// If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
+#undef WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <math.h>
+#include <stdint.h>
+#include <time.h>
+
+#if USE(QUERY_PERFORMANCE_COUNTER)
+#if OS(WINCE)
+extern "C" time_t mktime(struct tm *t);
+#else
+#include <sys/timeb.h>
+#include <sys/types.h>
+#endif
+#endif
+
+#elif PLATFORM(GTK)
+#include <glib.h>
+#elif PLATFORM(WX)
+#include <wx/datetime.h>
+#elif PLATFORM(EFL)
+#include <Ecore.h>
+#else
+#include <sys/time.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QElapsedTimer>
+#endif
+
+#if PLATFORM(CHROMIUM)
+#error Chromium uses a different timer implementation
+#endif
+
+namespace WTF {
+
+const double msPerSecond = 1000.0;
+
+#if OS(WINDOWS)
+
+#if USE(QUERY_PERFORMANCE_COUNTER)
+
+static LARGE_INTEGER qpcFrequency;
+static bool syncedTime;
+
+static double highResUpTime()
+{
+ // We use QPC, but only after sanity checking its result, due to bugs:
+ // http://support.microsoft.com/kb/274323
+ // http://support.microsoft.com/kb/895980
+ // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("...you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL)."
+
+ static LARGE_INTEGER qpcLast;
+ static DWORD tickCountLast;
+ static bool inited;
+
+ LARGE_INTEGER qpc;
+ QueryPerformanceCounter(&qpc);
+ DWORD tickCount = GetTickCount();
+
+ if (inited) {
+ __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
+ __int64 tickCountElapsed;
+ if (tickCount >= tickCountLast)
+ tickCountElapsed = (tickCount - tickCountLast);
+ else {
+#if COMPILER(MINGW)
+ __int64 tickCountLarge = tickCount + 0x100000000ULL;
+#else
+ __int64 tickCountLarge = tickCount + 0x100000000I64;
+#endif
+ tickCountElapsed = tickCountLarge - tickCountLast;
+ }
+
+ // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
+ // (500ms value is from http://support.microsoft.com/kb/274323)
+ __int64 diff = tickCountElapsed - qpcElapsed;
+ if (diff > 500 || diff < -500)
+ syncedTime = false;
+ } else
+ inited = true;
+
+ qpcLast = qpc;
+ tickCountLast = tickCount;
+
+ return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
+}
+
+static double lowResUTCTime()
+{
+#if OS(WINCE)
+ SYSTEMTIME systemTime;
+ GetSystemTime(&systemTime);
+ struct tm tmtime;
+ tmtime.tm_year = systemTime.wYear - 1900;
+ tmtime.tm_mon = systemTime.wMonth - 1;
+ tmtime.tm_mday = systemTime.wDay;
+ tmtime.tm_wday = systemTime.wDayOfWeek;
+ tmtime.tm_hour = systemTime.wHour;
+ tmtime.tm_min = systemTime.wMinute;
+ tmtime.tm_sec = systemTime.wSecond;
+ time_t timet = mktime(&tmtime);
+ return timet * msPerSecond + systemTime.wMilliseconds;
+#else
+ struct _timeb timebuffer;
+ _ftime(&timebuffer);
+ return timebuffer.time * msPerSecond + timebuffer.millitm;
+#endif
+}
+
+static bool qpcAvailable()
+{
+ static bool available;
+ static bool checked;
+
+ if (checked)
+ return available;
+
+ available = QueryPerformanceFrequency(&qpcFrequency);
+ checked = true;
+ return available;
+}
+
+double currentTime()
+{
+ // Use a combination of ftime and QueryPerformanceCounter.
+ // ftime returns the information we want, but doesn't have sufficient resolution.
+ // 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 double syncLowResUTCTime;
+ static double syncHighResUpTime;
+ static double lastUTCTime;
+
+ double lowResTime = lowResUTCTime();
+
+ if (!qpcAvailable())
+ return lowResTime / 1000.0;
+
+ double highResTime = highResUpTime();
+
+ if (!syncedTime) {
+ timeBeginPeriod(1); // increase time resolution around low-res time getter
+ syncLowResUTCTime = lowResTime = lowResUTCTime();
+ timeEndPeriod(1); // restore time resolution
+ syncHighResUpTime = highResTime;
+ syncedTime = true;
+ }
+
+ double highResElapsed = highResTime - syncHighResUpTime;
+ double utc = syncLowResUTCTime + highResElapsed;
+
+ // force a clock re-sync if we've drifted
+ double lowResElapsed = lowResTime - syncLowResUTCTime;
+ const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
+ if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
+ syncedTime = false;
+
+ // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
+ const double backwardTimeLimit = 2000.0;
+ if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
+ return lastUTCTime / 1000.0;
+ lastUTCTime = utc;
+ return utc / 1000.0;
+}
+
+#else
+
+static double currentSystemTime()
+{
+ FILETIME ft;
+ GetCurrentFT(&ft);
+
+ // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
+ // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
+ // prevent alignment faults on 64-bit Windows).
+
+ ULARGE_INTEGER t;
+ memcpy(&t, &ft, sizeof(t));
+
+ // Windows file times are in 100s of nanoseconds.
+ // To convert to seconds, we have to divide by 10,000,000, which is more quickly
+ // done by multiplying by 0.0000001.
+
+ // Between January 1, 1601 and January 1, 1970, there were 369 complete years,
+ // of which 89 were leap years (1700, 1800, and 1900 were not leap years).
+ // That is a total of 134774 days, which is 11644473600 seconds.
+
+ return t.QuadPart * 0.0000001 - 11644473600.0;
+}
+
+double currentTime()
+{
+ static bool init = false;
+ static double lastTime;
+ static DWORD lastTickCount;
+ if (!init) {
+ lastTime = currentSystemTime();
+ lastTickCount = GetTickCount();
+ init = true;
+ return lastTime;
+ }
+
+ DWORD tickCountNow = GetTickCount();
+ DWORD elapsed = tickCountNow - lastTickCount;
+ double timeNow = lastTime + (double)elapsed / 1000.;
+ if (elapsed >= 0x7FFFFFFF) {
+ lastTime = timeNow;
+ lastTickCount = tickCountNow;
+ }
+ return timeNow;
+}
+
+#endif // USE(QUERY_PERFORMANCE_COUNTER)
+
+#elif PLATFORM(GTK)
+
+// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
+// better accuracy compared with Windows implementation of g_get_current_time:
+// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
+// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
+double currentTime()
+{
+ GTimeVal now;
+ g_get_current_time(&now);
+ return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
+}
+
+#elif PLATFORM(WX)
+
+double currentTime()
+{
+ wxDateTime now = wxDateTime::UNow();
+ return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
+}
+
+#elif PLATFORM(EFL)
+
+double currentTime()
+{
+ return ecore_time_unix_get();
+}
+
+#else
+
+double currentTime()
+{
+ struct timeval now;
+ gettimeofday(&now, 0);
+ return now.tv_sec + now.tv_usec / 1000000.0;
+}
+
+#endif
+
+#if PLATFORM(MAC)
+
+double monotonicallyIncreasingTime()
+{
+ // Based on listing #2 from Apple QA 1398.
+ static mach_timebase_info_data_t timebaseInfo;
+ if (!timebaseInfo.denom) {
+ kern_return_t kr = mach_timebase_info(&timebaseInfo);
+ ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
+ }
+ return (mach_absolute_time() * timebaseInfo.numer) / (1.0e9 * timebaseInfo.denom);
+}
+
+#elif PLATFORM(EFL)
+
+double monotonicallyIncreasingTime()
+{
+ return ecore_time_get();
+}
+
+#elif PLATFORM(GTK)
+
+double monotonicallyIncreasingTime()
+{
+ return static_cast<double>(g_get_monotonic_time() / 1000000.0);
+}
+
+#elif PLATFORM(QT)
+
+double monotonicallyIncreasingTime()
+{
+ ASSERT(QElapsedTimer::isMonotonic());
+ static QElapsedTimer timer;
+ return timer.nsecsElapsed() / 1.0e9;
+}
+
+#else
+
+double monotonicallyIncreasingTime()
+{
+ static double lastTime = 0;
+ double currentTimeNow = currentTime();
+ if (currentTimeNow < lastTime)
+ return lastTime;
+ lastTime = currentTimeNow;
+ return currentTimeNow;
+}
+
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/CurrentTime.h b/Source/JavaScriptCore/wtf/CurrentTime.h
new file mode 100644
index 000000000..71775c273
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/CurrentTime.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 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 CurrentTime_h
+#define CurrentTime_h
+
+#include <time.h>
+
+namespace WTF {
+
+// Returns the current UTC time in seconds, counted from January 1, 1970.
+// Precision varies depending on platform but is usually as good or better
+// than a millisecond.
+double currentTime();
+
+// Same thing, in milliseconds.
+inline double currentTimeMS()
+{
+ return currentTime() * 1000.0;
+}
+
+inline void getLocalTime(const time_t* localTime, struct tm* localTM)
+{
+#if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE)
+ *localTM = *localtime(localTime);
+#elif COMPILER(MSVC)
+ localtime_s(localTM, localTime);
+#else
+ localtime_r(localTime, localTM);
+#endif
+}
+
+// Provides a monotonically increasing time in seconds since an arbitrary point in the past.
+// On unsupported platforms, this function only guarantees the result will be non-decreasing.
+double monotonicallyIncreasingTime();
+
+} // namespace WTF
+
+using WTF::currentTime;
+using WTF::currentTimeMS;
+using WTF::getLocalTime;
+using WTF::monotonicallyIncreasingTime;
+
+#endif // CurrentTime_h
diff --git a/Source/JavaScriptCore/wtf/DateMath.cpp b/Source/JavaScriptCore/wtf/DateMath.cpp
new file mode 100644
index 000000000..86bd99527
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DateMath.cpp
@@ -0,0 +1,1062 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * 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.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. 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.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.
+
+ * Copyright 2006-2008 the V8 project authors. 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 "DateMath.h"
+
+#include "Assertions.h"
+#include "ASCIICType.h"
+#include "CurrentTime.h"
+#include "MathExtras.h"
+#include "StdLibExtras.h"
+#include "StringExtras.h"
+
+#include <algorithm>
+#include <limits.h>
+#include <limits>
+#include <stdint.h>
+#include <time.h>
+#include <wtf/text/StringBuilder.h>
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+#if OS(WINCE)
+extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t);
+extern "C" struct tm * localtime(const time_t *timer);
+#endif
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if HAVE(SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+
+using namespace WTF;
+
+namespace WTF {
+
+/* Constants */
+
+static const double minutesPerDay = 24.0 * 60.0;
+static const double secondsPerDay = 24.0 * 60.0 * 60.0;
+static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
+
+static const double usecPerSec = 1000000.0;
+
+static const double maxUnixTime = 2145859200.0; // 12/31/2037
+// ECMAScript asks not to support for a date of which total
+// millisecond value is larger than the following value.
+// See 15.9.1.14 of ECMA-262 5th edition.
+static const double maxECMAScriptTime = 8.64E15;
+
+// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
+// First for non-leap years, then for leap years.
+static const int firstDayOfMonth[2][12] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
+};
+
+bool isLeapYear(int year)
+{
+ if (year % 4 != 0)
+ return false;
+ if (year % 400 == 0)
+ return true;
+ if (year % 100 == 0)
+ return false;
+ return true;
+}
+
+static inline int daysInYear(int year)
+{
+ return 365 + isLeapYear(year);
+}
+
+static inline double daysFrom1970ToYear(int year)
+{
+ // The Gregorian Calendar rules for leap years:
+ // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
+ // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
+ // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
+
+ static const int leapDaysBefore1971By4Rule = 1970 / 4;
+ static const int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
+ static const int leapDaysBefore1971By400Rule = 1970 / 400;
+
+ const double yearMinusOne = year - 1;
+ const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
+ const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
+ const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
+
+ return 365.0 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
+}
+
+double msToDays(double ms)
+{
+ return floor(ms / msPerDay);
+}
+
+static String twoDigitStringFromNumber(int number)
+{
+ ASSERT(number >= 0 && number < 100);
+ if (number > 9)
+ return String::number(number);
+ return makeString("0", String::number(number));
+}
+
+int msToYear(double ms)
+{
+ int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
+ double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
+ if (msFromApproxYearTo1970 > ms)
+ return approxYear - 1;
+ if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
+ return approxYear + 1;
+ return approxYear;
+}
+
+int dayInYear(double ms, int year)
+{
+ return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
+}
+
+static inline double msToMilliseconds(double ms)
+{
+ double result = fmod(ms, msPerDay);
+ if (result < 0)
+ result += msPerDay;
+ return result;
+}
+
+int msToMinutes(double ms)
+{
+ double result = fmod(floor(ms / msPerMinute), minutesPerHour);
+ if (result < 0)
+ result += minutesPerHour;
+ return static_cast<int>(result);
+}
+
+int msToHours(double ms)
+{
+ double result = fmod(floor(ms/msPerHour), hoursPerDay);
+ if (result < 0)
+ result += hoursPerDay;
+ return static_cast<int>(result);
+}
+
+int monthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+
+ if (d < (step = 31))
+ return 0;
+ step += (leapYear ? 29 : 28);
+ if (d < step)
+ return 1;
+ if (d < (step += 31))
+ return 2;
+ if (d < (step += 30))
+ return 3;
+ if (d < (step += 31))
+ return 4;
+ if (d < (step += 30))
+ return 5;
+ if (d < (step += 31))
+ return 6;
+ if (d < (step += 31))
+ return 7;
+ if (d < (step += 30))
+ return 8;
+ if (d < (step += 31))
+ return 9;
+ if (d < (step += 30))
+ return 10;
+ return 11;
+}
+
+static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth)
+{
+ startDayOfThisMonth = startDayOfNextMonth;
+ startDayOfNextMonth += daysInThisMonth;
+ return (dayInYear <= startDayOfNextMonth);
+}
+
+int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+ int next = 30;
+
+ if (d <= next)
+ return d + 1;
+ const int daysInFeb = (leapYear ? 29 : 28);
+ if (checkMonth(d, step, next, daysInFeb))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ step = next;
+ return d - step;
+}
+
+static inline int monthToDayInYear(int month, bool isLeapYear)
+{
+ return firstDayOfMonth[isLeapYear][month];
+}
+
+double dateToDaysFrom1970(int year, int month, int day)
+{
+ year += month / 12;
+
+ month %= 12;
+ if (month < 0) {
+ month += 12;
+ --year;
+ }
+
+ double yearday = floor(daysFrom1970ToYear(year));
+ ASSERT((year >= 1970 && yearday >= 0) || (year < 1970 && yearday < 0));
+ int monthday = monthToDayInYear(month, isLeapYear(year));
+
+ return yearday + monthday + day - 1;
+}
+
+// There is a hard limit at 2038 that we currently do not have a workaround
+// for (rdar://problem/5052975).
+static inline int maximumYearForDST()
+{
+ return 2037;
+}
+
+static inline int minimumYearForDST()
+{
+ // Because of the 2038 issue (see maximumYearForDST) if the current year is
+ // greater than the max year minus 27 (2010), we want to use the max year
+ // minus 27 instead, to ensure there is a range of 28 years that all years
+ // can map to.
+ return std::min(msToYear(jsCurrentTime()), maximumYearForDST() - 27) ;
+}
+
+/*
+ * Find an equivalent year for the one given, where equivalence is deterined by
+ * the two years having the same leapness and the first day of the year, falling
+ * on the same day of the week.
+ *
+ * This function returns a year between this current year and 2037, however this
+ * function will potentially return incorrect results if the current year is after
+ * 2010, (rdar://problem/5052975), if the year passed in is before 1900 or after
+ * 2100, (rdar://problem/5055038).
+ */
+int equivalentYearForDST(int year)
+{
+ // It is ok if the cached year is not the current year as long as the rules
+ // for DST did not change between the two years; if they did the app would need
+ // to be restarted.
+ static int minYear = minimumYearForDST();
+ int maxYear = maximumYearForDST();
+
+ int difference;
+ if (year > maxYear)
+ difference = minYear - year;
+ else if (year < minYear)
+ difference = maxYear - year;
+ else
+ return year;
+
+ int quotient = difference / 28;
+ int product = (quotient) * 28;
+
+ year += product;
+ ASSERT((year >= minYear && year <= maxYear) || (product - year == static_cast<int>(std::numeric_limits<double>::quiet_NaN())));
+ return year;
+}
+
+int32_t calculateUTCOffset()
+{
+ time_t localTime = time(0);
+ tm localt;
+ getLocalTime(&localTime, &localt);
+
+ // Get the difference between this time zone and UTC on the 1st of January of this year.
+ localt.tm_sec = 0;
+ localt.tm_min = 0;
+ localt.tm_hour = 0;
+ localt.tm_mday = 1;
+ localt.tm_mon = 0;
+ // Not setting localt.tm_year!
+ localt.tm_wday = 0;
+ localt.tm_yday = 0;
+ localt.tm_isdst = 0;
+#if HAVE(TM_GMTOFF)
+ localt.tm_gmtoff = 0;
+#endif
+#if HAVE(TM_ZONE)
+ localt.tm_zone = 0;
+#endif
+
+#if HAVE(TIMEGM)
+ time_t utcOffset = timegm(&localt) - mktime(&localt);
+#else
+ // Using a canned date of 01/01/2009 on platforms with weaker date-handling foo.
+ localt.tm_year = 109;
+ time_t utcOffset = 1230768000 - mktime(&localt);
+#endif
+
+ return static_cast<int32_t>(utcOffset * 1000);
+}
+
+/*
+ * Get the DST offset for the time passed in.
+ */
+static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset)
+{
+ if (localTimeSeconds > maxUnixTime)
+ localTimeSeconds = maxUnixTime;
+ else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
+ localTimeSeconds += secondsPerDay;
+
+ //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
+ double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset;
+
+ // Offset from UTC but doesn't include DST obviously
+ int offsetHour = msToHours(offsetTime);
+ int offsetMinute = msToMinutes(offsetTime);
+
+ // FIXME: time_t has a potential problem in 2038
+ time_t localTime = static_cast<time_t>(localTimeSeconds);
+
+ tm localTM;
+ getLocalTime(&localTime, &localTM);
+
+ double diff = ((localTM.tm_hour - offsetHour) * secondsPerHour) + ((localTM.tm_min - offsetMinute) * 60);
+
+ if (diff < 0)
+ diff += secondsPerDay;
+
+ return (diff * msPerSecond);
+}
+
+// Get the DST offset, given a time in UTC
+double calculateDSTOffset(double ms, double utcOffset)
+{
+ // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
+ // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
+ // standard explicitly dictates that historical information should not be considered when
+ // determining DST. For this reason we shift away from years that localtime can handle but would
+ // return historically accurate information.
+ int year = msToYear(ms);
+ int equivalentYear = equivalentYearForDST(year);
+ if (year != equivalentYear) {
+ bool leapYear = isLeapYear(year);
+ int dayInYearLocal = dayInYear(ms, year);
+ int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear);
+ int month = monthFromDayInYear(dayInYearLocal, leapYear);
+ double day = dateToDaysFrom1970(equivalentYear, month, dayInMonth);
+ ms = (day * msPerDay) + msToMilliseconds(ms);
+ }
+
+ return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset);
+}
+
+void initializeDates()
+{
+#if !ASSERT_DISABLED
+ static bool alreadyInitialized;
+ ASSERT(!alreadyInitialized);
+ alreadyInitialized = true;
+#endif
+
+ 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, double second)
+{
+ double days = (day - 32075)
+ + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
+ + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
+ - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
+ - 2440588;
+ return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
+}
+
+// We follow the recommendation of RFC 2822 to consider all
+// obsolete time zones not listed here equivalent to "-0000".
+static const struct KnownZone {
+#if !OS(WINDOWS)
+ const
+#endif
+ char tzName[4];
+ int tzOffset;
+} known_zones[] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -300 },
+ { "EDT", -240 },
+ { "CST", -360 },
+ { "CDT", -300 },
+ { "MST", -420 },
+ { "MDT", -360 },
+ { "PST", -480 },
+ { "PDT", -420 }
+};
+
+inline static void skipSpacesAndComments(const char*& s)
+{
+ int nesting = 0;
+ char ch;
+ while ((ch = *s)) {
+ if (!isASCIISpace(ch)) {
+ if (ch == '(')
+ nesting++;
+ else if (ch == ')' && nesting > 0)
+ nesting--;
+ else if (nesting == 0)
+ break;
+ }
+ s++;
+ }
+}
+
+// returns 0-11 (Jan-Dec); -1 on failure
+static int findMonth(const char* monthStr)
+{
+ ASSERT(monthStr);
+ char needle[4];
+ for (int i = 0; i < 3; ++i) {
+ if (!*monthStr)
+ return -1;
+ needle[i] = static_cast<char>(toASCIILower(*monthStr++));
+ }
+ needle[3] = '\0';
+ const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
+ const char *str = strstr(haystack, needle);
+ if (str) {
+ int position = static_cast<int>(str - haystack);
+ if (position % 3 == 0)
+ return position / 3;
+ }
+ return -1;
+}
+
+static bool parseLong(const char* string, char** stopPosition, int base, long* result)
+{
+ *result = strtol(string, stopPosition, base);
+ // Avoid the use of errno as it is not available on Windows CE
+ if (string == *stopPosition || *result == LONG_MIN || *result == LONG_MAX)
+ return false;
+ return true;
+}
+
+// Parses a date with the format YYYY[-MM[-DD]].
+// Year parsing is lenient, allows any number of digits, and +/-.
+// Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string.
+static char* parseES5DatePortion(const char* currentPosition, long& year, long& month, long& day)
+{
+ 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.
+ if (!parseLong(currentPosition, &postParsePosition, 10, &year))
+ return 0;
+
+ // Check for presence of -MM portion.
+ if (*postParsePosition != '-')
+ return postParsePosition;
+ currentPosition = postParsePosition + 1;
+
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &month))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+
+ // Check for presence of -DD portion.
+ if (*postParsePosition != '-')
+ return postParsePosition;
+ currentPosition = postParsePosition + 1;
+
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &day))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ return postParsePosition;
+}
+
+// Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)00:00].
+// Fractional seconds parsing is lenient, allows any number of digits.
+// Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string.
+static char* parseES5TimePortion(char* currentPosition, long& hours, long& minutes, double& seconds, long& timeZoneSeconds)
+{
+ char* postParsePosition;
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &hours))
+ return 0;
+ if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+ return 0;
+ currentPosition = postParsePosition + 1;
+
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &minutes))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ currentPosition = postParsePosition;
+
+ // Seconds are optional.
+ if (*currentPosition == ':') {
+ ++currentPosition;
+
+ long intSeconds;
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ 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 0;
+
+ // We are more lenient than ES5 by accepting more or less than 3 fraction digits.
+ long fracSeconds;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds))
+ return 0;
+
+ long numFracDigits = postParsePosition - currentPosition;
+ seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigits));
+ }
+ currentPosition = postParsePosition;
+ }
+
+ if (*currentPosition == 'Z')
+ return currentPosition + 1;
+
+ bool tzNegative;
+ if (*currentPosition == '-')
+ tzNegative = true;
+ else if (*currentPosition == '+')
+ tzNegative = false;
+ else
+ return currentPosition; // no timezone
+ ++currentPosition;
+
+ long tzHours;
+ long tzHoursAbs;
+ long tzMinutes;
+
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours))
+ return 0;
+ if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+ return 0;
+ tzHoursAbs = labs(tzHours);
+ currentPosition = postParsePosition + 1;
+
+ if (!isASCIIDigit(*currentPosition))
+ return 0;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes))
+ return 0;
+ if ((postParsePosition - currentPosition) != 2)
+ return 0;
+ currentPosition = postParsePosition;
+
+ if (tzHoursAbs > 24)
+ return 0;
+ if (tzMinutes < 0 || tzMinutes > 59)
+ return 0;
+
+ timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs));
+ if (tzNegative)
+ timeZoneSeconds = -timeZoneSeconds;
+
+ return currentPosition;
+}
+
+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 };
+
+ // The year must be present, but the other fields may be omitted - see ES5.1 15.9.1.15.
+ long year = 0;
+ long month = 1;
+ long day = 1;
+ long hours = 0;
+ long minutes = 0;
+ double seconds = 0;
+ long timeZoneSeconds = 0;
+
+ // Parse the date YYYY[-MM[-DD]]
+ char* currentPosition = parseES5DatePortion(dateString, year, month, day);
+ if (!currentPosition)
+ return std::numeric_limits<double>::quiet_NaN();
+ // Look for a time portion.
+ if (*currentPosition == 'T') {
+ // Parse the time HH:mm[:ss[.sss]][Z|(+|-)00:00]
+ currentPosition = parseES5TimePortion(currentPosition + 1, hours, minutes, seconds, timeZoneSeconds);
+ if (!currentPosition)
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+ // Check that we have parsed all characters in the string.
+ if (*currentPosition)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // 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 std::numeric_limits<double>::quiet_NaN();
+ if (day < 1 || day > daysPerMonth[month - 1])
+ return std::numeric_limits<double>::quiet_NaN();
+ if (month == 2 && day > 28 && !isLeapYear(year))
+ return std::numeric_limits<double>::quiet_NaN();
+ if (hours < 0 || hours > 24)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (hours == 24 && (minutes || seconds))
+ return std::numeric_limits<double>::quiet_NaN();
+ if (minutes < 0 || minutes > 59)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (seconds < 0 || seconds >= 61)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (seconds > 60) {
+ // Discard leap seconds by clamping to the end of a minute.
+ seconds = 60;
+ }
+
+ 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.
+double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset)
+{
+ haveTZ = false;
+ offset = 0;
+
+ // This parses a date in the form:
+ // Tuesday, 09-Nov-99 23:12:40 GMT
+ // or
+ // Sat, 01-Jan-2000 08:00:00 GMT
+ // or
+ // Sat, 01 Jan 2000 08:00:00 GMT
+ // or
+ // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
+ // ### non RFC formats, added for Javascript:
+ // [Wednesday] January 09 1999 23:12:40 GMT
+ // [Wednesday] January 09 23:12:40 GMT 1999
+ //
+ // We ignore the weekday.
+
+ // Skip leading space
+ skipSpacesAndComments(dateString);
+
+ long month = -1;
+ const char *wordStart = dateString;
+ // Check contents of first words if not number
+ while (*dateString && !isASCIIDigit(*dateString)) {
+ if (isASCIISpace(*dateString) || *dateString == '(') {
+ if (dateString - wordStart >= 3)
+ month = findMonth(wordStart);
+ skipSpacesAndComments(dateString);
+ wordStart = dateString;
+ } else
+ dateString++;
+ }
+
+ // Missing delimiter between month and day (like "January29")?
+ if (month == -1 && wordStart != dateString)
+ month = findMonth(wordStart);
+
+ skipSpacesAndComments(dateString);
+
+ if (!*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // ' 09-Nov-99 23:12:40 GMT'
+ char* newPosStr;
+ long day;
+ if (!parseLong(dateString, &newPosStr, 10, &day))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+
+ if (!*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ if (day < 0)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ long year = 0;
+ if (day > 31) {
+ // ### where is the boundary and what happens below?
+ if (*dateString != '/')
+ return std::numeric_limits<double>::quiet_NaN();
+ // looks like a YYYY/MM/DD date
+ if (!*++dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+ year = day;
+ if (!parseLong(dateString, &newPosStr, 10, &month))
+ return std::numeric_limits<double>::quiet_NaN();
+ month -= 1;
+ dateString = newPosStr;
+ if (*dateString++ != '/' || !*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (!parseLong(dateString, &newPosStr, 10, &day))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+ } else if (*dateString == '/' && month == -1) {
+ dateString++;
+ // This looks like a MM/DD/YYYY date, not an RFC date.
+ month = day - 1; // 0-based
+ if (!parseLong(dateString, &newPosStr, 10, &day))
+ return std::numeric_limits<double>::quiet_NaN();
+ if (day < 1 || day > 31)
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+ if (*dateString == '/')
+ dateString++;
+ if (!*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+ } else {
+ if (*dateString == '-')
+ dateString++;
+
+ skipSpacesAndComments(dateString);
+
+ if (*dateString == ',')
+ dateString++;
+
+ if (month == -1) { // not found yet
+ month = findMonth(dateString);
+ if (month == -1)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
+ dateString++;
+
+ if (!*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // '-99 23:12:40 GMT'
+ if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString++;
+ }
+ }
+
+ if (month < 0 || month > 11)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // '99 23:12:40 GMT'
+ if (year <= 0 && *dateString) {
+ if (!parseLong(dateString, &newPosStr, 10, &year))
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ // Don't fail if the time is missing.
+ long hour = 0;
+ long minute = 0;
+ long second = 0;
+ if (!*newPosStr)
+ dateString = newPosStr;
+ else {
+ // ' 23:12:40 GMT'
+ if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
+ if (*newPosStr != ':')
+ return std::numeric_limits<double>::quiet_NaN();
+ // There was no year; the number was the hour.
+ year = -1;
+ } else {
+ // in the normal case (we parsed the year), advance to the next number
+ dateString = ++newPosStr;
+ skipSpacesAndComments(dateString);
+ }
+
+ parseLong(dateString, &newPosStr, 10, &hour);
+ // Do not check for errno here since we want to continue
+ // even if errno was set becasue we are still looking
+ // for the timezone!
+
+ // Read a number? If not, this might be a timezone name.
+ if (newPosStr != dateString) {
+ dateString = newPosStr;
+
+ if (hour < 0 || hour > 23)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ if (!*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // ':12:40 GMT'
+ if (*dateString++ != ':')
+ return std::numeric_limits<double>::quiet_NaN();
+
+ if (!parseLong(dateString, &newPosStr, 10, &minute))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+
+ if (minute < 0 || minute > 59)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // ':40 GMT'
+ if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // seconds are optional in rfc822 + rfc2822
+ if (*dateString ==':') {
+ dateString++;
+
+ if (!parseLong(dateString, &newPosStr, 10, &second))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+
+ if (second < 0 || second > 59)
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ skipSpacesAndComments(dateString);
+
+ if (strncasecmp(dateString, "AM", 2) == 0) {
+ if (hour > 12)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (hour == 12)
+ hour = 0;
+ dateString += 2;
+ skipSpacesAndComments(dateString);
+ } else if (strncasecmp(dateString, "PM", 2) == 0) {
+ if (hour > 12)
+ return std::numeric_limits<double>::quiet_NaN();
+ if (hour != 12)
+ hour += 12;
+ dateString += 2;
+ skipSpacesAndComments(dateString);
+ }
+ }
+ }
+
+ // Don't fail if the time zone is missing.
+ // Some websites omit the time zone (4275206).
+ if (*dateString) {
+ if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
+ dateString += 3;
+ haveTZ = true;
+ }
+
+ if (*dateString == '+' || *dateString == '-') {
+ long o;
+ if (!parseLong(dateString, &newPosStr, 10, &o))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+
+ if (o < -9959 || o > 9959)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ int sgn = (o < 0) ? -1 : 1;
+ o = labs(o);
+ if (*dateString != ':') {
+ if (o >= 24)
+ offset = ((o / 100) * 60 + (o % 100)) * sgn;
+ else
+ offset = o * 60 * sgn;
+ } else { // GMT+05:00
+ long o2;
+ if (!parseLong(dateString, &newPosStr, 10, &o2))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+ offset = (o * 60 + o2) * sgn;
+ }
+ haveTZ = true;
+ } else {
+ 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);
+ haveTZ = true;
+ break;
+ }
+ }
+ }
+ }
+
+ skipSpacesAndComments(dateString);
+
+ if (*dateString && year == -1) {
+ if (!parseLong(dateString, &newPosStr, 10, &year))
+ return std::numeric_limits<double>::quiet_NaN();
+ dateString = newPosStr;
+ }
+
+ skipSpacesAndComments(dateString);
+
+ // Trailing garbage
+ if (*dateString)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // Y2K: Handle 2 digit years.
+ if (year >= 0 && year < 100) {
+ if (year < 50)
+ year += 2000;
+ else
+ year += 1900;
+ }
+
+ return ymdhmsToSeconds(year, month + 1, day, hour, minute, second) * msPerSecond;
+}
+
+double parseDateFromNullTerminatedCharacters(const char* dateString)
+{
+ bool haveTZ;
+ int offset;
+ double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
+ if (isnan(ms))
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // fall back to local timezone
+ if (!haveTZ) {
+ double utcOffset = calculateUTCOffset();
+ double dstOffset = calculateDSTOffset(ms, utcOffset);
+ offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+ }
+ return ms - (offset * msPerMinute);
+}
+
+double timeClip(double t)
+{
+ if (!isfinite(t))
+ return std::numeric_limits<double>::quiet_NaN();
+ if (fabs(t) > maxECMAScriptTime)
+ return std::numeric_limits<double>::quiet_NaN();
+ return trunc(t);
+}
+
+// See http://tools.ietf.org/html/rfc2822#section-3.3 for more information.
+String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset)
+{
+ StringBuilder stringBuilder;
+ stringBuilder.append(weekdayName[dayOfWeek]);
+ stringBuilder.append(", ");
+ stringBuilder.append(String::number(day));
+ stringBuilder.append(" ");
+ stringBuilder.append(monthName[month]);
+ stringBuilder.append(" ");
+ stringBuilder.append(String::number(year));
+ stringBuilder.append(" ");
+
+ stringBuilder.append(twoDigitStringFromNumber(hours));
+ stringBuilder.append(':');
+ stringBuilder.append(twoDigitStringFromNumber(minutes));
+ stringBuilder.append(':');
+ stringBuilder.append(twoDigitStringFromNumber(seconds));
+ stringBuilder.append(' ');
+
+ stringBuilder.append(utcOffset > 0 ? "+" : "-");
+ int absoluteUTCOffset = abs(utcOffset);
+ stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset / 60));
+ stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset % 60));
+
+ return stringBuilder.toString();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/DateMath.h b/Source/JavaScriptCore/wtf/DateMath.h
new file mode 100644
index 000000000..114acf8a8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DateMath.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Research In Motion Limited. All rights reserved.
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ */
+
+#ifndef DateMath_h
+#define DateMath_h
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/UnusedParam.h>
+
+namespace WTF {
+
+void initializeDates();
+int equivalentYearForDST(int year);
+
+// 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 parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset);
+double timeClip(double);
+// dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011, hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720].
+String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset);
+
+inline double jsCurrentTime()
+{
+ // JavaScript doesn't recognize fractions of a millisecond.
+ return floor(WTF::currentTimeMS());
+}
+
+const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+const double hoursPerDay = 24.0;
+const double minutesPerHour = 60.0;
+const double secondsPerHour = 60.0 * 60.0;
+const double secondsPerMinute = 60.0;
+const double msPerSecond = 1000.0;
+const double msPerMinute = 60.0 * 1000.0;
+const double msPerHour = 60.0 * 60.0 * 1000.0;
+const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0;
+const double msPerMonth = 2592000000.0;
+
+bool isLeapYear(int year);
+
+// Returns the number of days from 1970-01-01 to the specified date.
+double dateToDaysFrom1970(int year, int month, int day);
+int msToYear(double ms);
+double msToDays(double ms);
+int msToMinutes(double ms);
+int msToHours(double ms);
+int dayInYear(double ms, int year);
+int monthFromDayInYear(int dayInYear, bool leapYear);
+int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
+
+// Returns offset milliseconds for UTC and DST.
+int32_t calculateUTCOffset();
+double calculateDSTOffset(double ms, double utcOffset);
+
+} // namespace WTF
+
+using WTF::isLeapYear;
+using WTF::dateToDaysFrom1970;
+using WTF::dayInMonthFromDayInYear;
+using WTF::dayInYear;
+using WTF::minutesPerHour;
+using WTF::monthFromDayInYear;
+using WTF::msPerDay;
+using WTF::msPerMinute;
+using WTF::msPerSecond;
+using WTF::msToYear;
+using WTF::msToDays;
+using WTF::msToMinutes;
+using WTF::msToHours;
+using WTF::secondsPerMinute;
+using WTF::parseDateFromNullTerminatedCharacters;
+using WTF::makeRFC2822DateString;
+using WTF::calculateUTCOffset;
+using WTF::calculateDSTOffset;
+
+#endif // DateMath_h
diff --git a/Source/JavaScriptCore/wtf/DecimalNumber.cpp b/Source/JavaScriptCore/wtf/DecimalNumber.cpp
new file mode 100644
index 000000000..70304e2e5
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/DecimalNumber.h b/Source/JavaScriptCore/wtf/DecimalNumber.h
new file mode 100644
index 000000000..ac7b80058
--- /dev/null
+++ b/Source/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(isfinite(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(isfinite(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(isfinite(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/Source/JavaScriptCore/wtf/Decoder.h b/Source/JavaScriptCore/wtf/Decoder.h
new file mode 100644
index 000000000..341d58d73
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Decoder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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 Decoder_h
+#define Decoder_h
+
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+class String;
+
+class Decoder {
+protected:
+ Decoder() { }
+ virtual ~Decoder() { }
+
+public:
+ virtual bool decodeBytes(Vector<uint8_t>&) = 0;
+
+ virtual bool decodeBool(bool&) = 0;
+ virtual bool decodeUInt32(uint32_t&) = 0;
+ virtual bool decodeUInt64(uint64_t&) = 0;
+ virtual bool decodeInt32(int32_t&) = 0;
+ virtual bool decodeInt64(int64_t&) = 0;
+ virtual bool decodeFloat(float&) = 0;
+ virtual bool decodeDouble(double&) = 0;
+ virtual bool decodeString(String&) = 0;
+};
+
+} // namespace WTF
+
+using WTF::Decoder;
+
+#endif // Decoder_h
diff --git a/Source/JavaScriptCore/wtf/Deque.h b/Source/JavaScriptCore/wtf/Deque.h
new file mode 100644
index 000000000..18eb10582
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Deque.h
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 WTF_Deque_h
+#define WTF_Deque_h
+
+// FIXME: Could move what Vector and Deque share into a separate file.
+// Deque doesn't actually use Vector.
+
+#include "PassTraits.h"
+#include "Vector.h"
+
+namespace WTF {
+
+ template<typename T, size_t inlineCapacity> class DequeIteratorBase;
+ template<typename T, size_t inlineCapacity> class DequeIterator;
+ template<typename T, size_t inlineCapacity> class DequeConstIterator;
+ template<typename T, size_t inlineCapacity> class DequeReverseIterator;
+ template<typename T, size_t inlineCapacity> class DequeConstReverseIterator;
+
+ template<typename T, size_t inlineCapacity = 0>
+ class Deque {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ typedef DequeIterator<T, inlineCapacity> iterator;
+ typedef DequeConstIterator<T, inlineCapacity> const_iterator;
+ typedef DequeReverseIterator<T, inlineCapacity> reverse_iterator;
+ typedef DequeConstReverseIterator<T, inlineCapacity> const_reverse_iterator;
+ typedef PassTraits<T> Pass;
+ typedef typename PassTraits<T>::PassType PassType;
+
+ Deque();
+ Deque(const Deque<T, inlineCapacity>&);
+ Deque& operator=(const Deque<T, inlineCapacity>&);
+ ~Deque();
+
+ void swap(Deque<T, inlineCapacity>&);
+
+ size_t size() const { return m_start <= m_end ? m_end - m_start : m_end + m_buffer.capacity() - m_start; }
+ bool isEmpty() const { return m_start == m_end; }
+
+ iterator begin() { return iterator(this, m_start); }
+ iterator end() { return iterator(this, m_end); }
+ const_iterator begin() const { return const_iterator(this, m_start); }
+ const_iterator end() const { return const_iterator(this, m_end); }
+ reverse_iterator rbegin() { return reverse_iterator(this, m_end); }
+ reverse_iterator rend() { return reverse_iterator(this, m_start); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(this, m_end); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(this, m_start); }
+
+ 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]; }
+ PassType takeFirst();
+
+ T& last() { ASSERT(m_start != m_end); return *(--end()); }
+ const T& last() const { ASSERT(m_start != m_end); return *(--end()); }
+
+ template<typename U> void append(const U&);
+ template<typename U> void prepend(const U&);
+ void removeFirst();
+ void remove(iterator&);
+ void remove(const_iterator&);
+
+ void clear();
+
+ template<typename Predicate>
+ iterator findIf(Predicate&);
+
+ private:
+ friend class DequeIteratorBase<T, inlineCapacity>;
+
+ typedef VectorBuffer<T, inlineCapacity> Buffer;
+ typedef VectorTypeOperations<T> TypeOperations;
+ typedef DequeIteratorBase<T, inlineCapacity> IteratorBase;
+
+ void remove(size_t position);
+ void invalidateIterators();
+ void destroyAll();
+ void checkValidity() const;
+ void checkIndexValidity(size_t) const;
+ void expandCapacityIfNeeded();
+ void expandCapacity();
+
+ size_t m_start;
+ size_t m_end;
+ Buffer m_buffer;
+#ifndef NDEBUG
+ mutable IteratorBase* m_iterators;
+#endif
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeIteratorBase {
+ private:
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+
+ protected:
+ DequeIteratorBase();
+ DequeIteratorBase(const Deque<T, inlineCapacity>*, size_t);
+ DequeIteratorBase(const Base&);
+ Base& operator=(const Base&);
+ ~DequeIteratorBase();
+
+ void assign(const Base& other) { *this = other; }
+
+ void increment();
+ void decrement();
+
+ T* before() const;
+ T* after() const;
+
+ bool isEqual(const Base&) const;
+
+ private:
+ void addToIteratorsList();
+ void removeFromIteratorsList();
+ void checkValidity() const;
+ void checkValidity(const Base&) const;
+
+ Deque<T, inlineCapacity>* m_deque;
+ size_t m_index;
+
+ friend class Deque<T, inlineCapacity>;
+
+#ifndef NDEBUG
+ mutable DequeIteratorBase* m_next;
+ mutable DequeIteratorBase* m_previous;
+#endif
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeIterator : public DequeIteratorBase<T, inlineCapacity> {
+ private:
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeIterator<T, inlineCapacity> Iterator;
+
+ public:
+ DequeIterator(Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
+
+ DequeIterator(const Iterator& other) : Base(other) { }
+ DequeIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
+
+ T& operator*() const { return *Base::after(); }
+ T* operator->() const { return Base::after(); }
+
+ bool operator==(const Iterator& other) const { return Base::isEqual(other); }
+ bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
+
+ Iterator& operator++() { Base::increment(); return *this; }
+ // postfix ++ intentionally omitted
+ Iterator& operator--() { Base::decrement(); return *this; }
+ // postfix -- intentionally omitted
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeConstIterator : public DequeIteratorBase<T, inlineCapacity> {
+ private:
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeConstIterator<T, inlineCapacity> Iterator;
+ typedef DequeIterator<T, inlineCapacity> NonConstIterator;
+
+ public:
+ DequeConstIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
+
+ DequeConstIterator(const Iterator& other) : Base(other) { }
+ DequeConstIterator(const NonConstIterator& other) : Base(other) { }
+ DequeConstIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
+ DequeConstIterator& operator=(const NonConstIterator& other) { Base::assign(other); return *this; }
+
+ const T& operator*() const { return *Base::after(); }
+ const T* operator->() const { return Base::after(); }
+
+ bool operator==(const Iterator& other) const { return Base::isEqual(other); }
+ bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
+
+ Iterator& operator++() { Base::increment(); return *this; }
+ // postfix ++ intentionally omitted
+ Iterator& operator--() { Base::decrement(); return *this; }
+ // postfix -- intentionally omitted
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeReverseIterator : public DequeIteratorBase<T, inlineCapacity> {
+ private:
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeReverseIterator<T, inlineCapacity> Iterator;
+
+ public:
+ DequeReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
+
+ DequeReverseIterator(const Iterator& other) : Base(other) { }
+ DequeReverseIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
+
+ T& operator*() const { return *Base::before(); }
+ T* operator->() const { return Base::before(); }
+
+ bool operator==(const Iterator& other) const { return Base::isEqual(other); }
+ bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
+
+ Iterator& operator++() { Base::decrement(); return *this; }
+ // postfix ++ intentionally omitted
+ Iterator& operator--() { Base::increment(); return *this; }
+ // postfix -- intentionally omitted
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeConstReverseIterator : public DequeIteratorBase<T, inlineCapacity> {
+ private:
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeConstReverseIterator<T, inlineCapacity> Iterator;
+ typedef DequeReverseIterator<T, inlineCapacity> NonConstIterator;
+
+ public:
+ DequeConstReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
+
+ DequeConstReverseIterator(const Iterator& other) : Base(other) { }
+ DequeConstReverseIterator(const NonConstIterator& other) : Base(other) { }
+ DequeConstReverseIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
+ DequeConstReverseIterator& operator=(const NonConstIterator& other) { Base::assign(other); return *this; }
+
+ const T& operator*() const { return *Base::before(); }
+ const T* operator->() const { return Base::before(); }
+
+ bool operator==(const Iterator& other) const { return Base::isEqual(other); }
+ bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
+
+ Iterator& operator++() { Base::decrement(); return *this; }
+ // postfix ++ intentionally omitted
+ Iterator& operator--() { Base::increment(); return *this; }
+ // postfix -- intentionally omitted
+ };
+
+#ifdef NDEBUG
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkValidity() const { }
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkIndexValidity(size_t) const { }
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::invalidateIterators() { }
+#else
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::checkValidity() const
+ {
+ // In this implementation a capacity of 1 would confuse append() and
+ // other places that assume the index after capacity - 1 is 0.
+ ASSERT(m_buffer.capacity() != 1);
+
+ if (!m_buffer.capacity()) {
+ ASSERT(!m_start);
+ ASSERT(!m_end);
+ } else {
+ ASSERT(m_start < m_buffer.capacity());
+ ASSERT(m_end < m_buffer.capacity());
+ }
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::checkIndexValidity(size_t index) const
+ {
+ ASSERT_UNUSED(index, index <= m_buffer.capacity());
+ if (m_start <= m_end) {
+ ASSERT(index >= m_start);
+ ASSERT(index <= m_end);
+ } else {
+ ASSERT(index >= m_start || index <= m_end);
+ }
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::invalidateIterators()
+ {
+ IteratorBase* next;
+ for (IteratorBase* p = m_iterators; p; p = next) {
+ next = p->m_next;
+ p->m_deque = 0;
+ p->m_next = 0;
+ p->m_previous = 0;
+ }
+ m_iterators = 0;
+ }
+#endif
+
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::Deque()
+ : m_start(0)
+ , m_end(0)
+#ifndef NDEBUG
+ , m_iterators(0)
+#endif
+ {
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::Deque(const Deque<T, inlineCapacity>& other)
+ : m_start(other.m_start)
+ , m_end(other.m_end)
+ , m_buffer(other.m_buffer.capacity())
+#ifndef NDEBUG
+ , m_iterators(0)
+#endif
+ {
+ const T* otherBuffer = other.m_buffer.buffer();
+ if (m_start <= m_end)
+ TypeOperations::uninitializedCopy(otherBuffer + m_start, otherBuffer + m_end, m_buffer.buffer() + m_start);
+ else {
+ TypeOperations::uninitializedCopy(otherBuffer, otherBuffer + m_end, m_buffer.buffer());
+ TypeOperations::uninitializedCopy(otherBuffer + m_start, otherBuffer + m_buffer.capacity(), m_buffer.buffer() + m_start);
+ }
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void deleteAllValues(const Deque<T, inlineCapacity>& collection)
+ {
+ typedef typename Deque<T, inlineCapacity>::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete *it;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>& Deque<T, inlineCapacity>::operator=(const Deque<T, inlineCapacity>& other)
+ {
+ // FIXME: This is inefficient if we're using an inline buffer and T is
+ // expensive to copy since it will copy the buffer twice instead of once.
+ Deque<T> copy(other);
+ swap(copy);
+ return *this;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::destroyAll()
+ {
+ if (m_start <= m_end)
+ TypeOperations::destruct(m_buffer.buffer() + m_start, m_buffer.buffer() + m_end);
+ else {
+ TypeOperations::destruct(m_buffer.buffer(), m_buffer.buffer() + m_end);
+ TypeOperations::destruct(m_buffer.buffer() + m_start, m_buffer.buffer() + m_buffer.capacity());
+ }
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::~Deque()
+ {
+ checkValidity();
+ invalidateIterators();
+ destroyAll();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::swap(Deque<T, inlineCapacity>& other)
+ {
+ checkValidity();
+ other.checkValidity();
+ invalidateIterators();
+ std::swap(m_start, other.m_start);
+ std::swap(m_end, other.m_end);
+ m_buffer.swap(other.m_buffer);
+ checkValidity();
+ other.checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::clear()
+ {
+ checkValidity();
+ invalidateIterators();
+ destroyAll();
+ m_start = 0;
+ m_end = 0;
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ template<typename Predicate>
+ inline DequeIterator<T, inlineCapacity> Deque<T, inlineCapacity>::findIf(Predicate& predicate)
+ {
+ iterator end_iterator = end();
+ for (iterator it = begin(); it != end_iterator; ++it) {
+ if (predicate(*it))
+ return it;
+ }
+ return end_iterator;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::expandCapacityIfNeeded()
+ {
+ if (m_start) {
+ if (m_end + 1 != m_start)
+ return;
+ } else if (m_end) {
+ if (m_end != m_buffer.capacity() - 1)
+ return;
+ } else if (m_buffer.capacity())
+ return;
+
+ expandCapacity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::expandCapacity()
+ {
+ checkValidity();
+ size_t oldCapacity = m_buffer.capacity();
+ size_t newCapacity = max(static_cast<size_t>(16), oldCapacity + oldCapacity / 4 + 1);
+ T* oldBuffer = m_buffer.buffer();
+ m_buffer.allocateBuffer(newCapacity);
+ if (m_start <= m_end)
+ TypeOperations::move(oldBuffer + m_start, oldBuffer + m_end, m_buffer.buffer() + m_start);
+ else {
+ TypeOperations::move(oldBuffer, oldBuffer + m_end, m_buffer.buffer());
+ size_t newStart = newCapacity - (oldCapacity - m_start);
+ TypeOperations::move(oldBuffer + m_start, oldBuffer + oldCapacity, m_buffer.buffer() + newStart);
+ m_start = newStart;
+ }
+ m_buffer.deallocateBuffer(oldBuffer);
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline typename Deque<T, inlineCapacity>::PassType Deque<T, inlineCapacity>::takeFirst()
+ {
+ T oldFirst = Pass::transfer(first());
+ removeFirst();
+ return Pass::transfer(oldFirst);
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Deque<T, inlineCapacity>::append(const U& value)
+ {
+ checkValidity();
+ expandCapacityIfNeeded();
+ new (NotNull, &m_buffer.buffer()[m_end]) T(value);
+ if (m_end == m_buffer.capacity() - 1)
+ m_end = 0;
+ else
+ ++m_end;
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Deque<T, inlineCapacity>::prepend(const U& value)
+ {
+ checkValidity();
+ expandCapacityIfNeeded();
+ if (!m_start)
+ m_start = m_buffer.capacity() - 1;
+ else
+ --m_start;
+ new (NotNull, &m_buffer.buffer()[m_start]) T(value);
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::removeFirst()
+ {
+ checkValidity();
+ invalidateIterators();
+ ASSERT(!isEmpty());
+ TypeOperations::destruct(&m_buffer.buffer()[m_start], &m_buffer.buffer()[m_start + 1]);
+ if (m_start == m_buffer.capacity() - 1)
+ m_start = 0;
+ else
+ ++m_start;
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(iterator& it)
+ {
+ it.checkValidity();
+ remove(it.m_index);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(const_iterator& it)
+ {
+ it.checkValidity();
+ remove(it.m_index);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(size_t position)
+ {
+ if (position == m_end)
+ return;
+
+ checkValidity();
+ invalidateIterators();
+
+ T* buffer = m_buffer.buffer();
+ TypeOperations::destruct(&buffer[position], &buffer[position + 1]);
+
+ // Find which segment of the circular buffer contained the remove element, and only move elements in that part.
+ if (position >= m_start) {
+ TypeOperations::moveOverlapping(buffer + m_start, buffer + position, buffer + m_start + 1);
+ m_start = (m_start + 1) % m_buffer.capacity();
+ } else {
+ TypeOperations::moveOverlapping(buffer + position + 1, buffer + m_end, buffer + position);
+ m_end = (m_end - 1 + m_buffer.capacity()) % m_buffer.capacity();
+ }
+ checkValidity();
+ }
+
+#ifdef NDEBUG
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity() const { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity(const DequeIteratorBase<T, inlineCapacity>&) const { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList() { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList() { }
+#else
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::checkValidity() const
+ {
+ ASSERT(m_deque);
+ m_deque->checkIndexValidity(m_index);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::checkValidity(const Base& other) const
+ {
+ checkValidity();
+ other.checkValidity();
+ ASSERT(m_deque == other.m_deque);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList()
+ {
+ if (!m_deque)
+ m_next = 0;
+ else {
+ m_next = m_deque->m_iterators;
+ m_deque->m_iterators = this;
+ if (m_next)
+ m_next->m_previous = this;
+ }
+ m_previous = 0;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList()
+ {
+ if (!m_deque) {
+ ASSERT(!m_next);
+ ASSERT(!m_previous);
+ } else {
+ if (m_next) {
+ ASSERT(m_next->m_previous == this);
+ m_next->m_previous = m_previous;
+ }
+ if (m_previous) {
+ ASSERT(m_deque->m_iterators != this);
+ ASSERT(m_previous->m_next == this);
+ m_previous->m_next = m_next;
+ } else {
+ ASSERT(m_deque->m_iterators == this);
+ m_deque->m_iterators = m_next;
+ }
+ }
+ m_next = 0;
+ m_previous = 0;
+ }
+#endif
+
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase()
+ : m_deque(0)
+ {
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Deque<T, inlineCapacity>* deque, size_t index)
+ : m_deque(const_cast<Deque<T, inlineCapacity>*>(deque))
+ , m_index(index)
+ {
+ addToIteratorsList();
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Base& other)
+ : m_deque(other.m_deque)
+ , m_index(other.m_index)
+ {
+ addToIteratorsList();
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>& DequeIteratorBase<T, inlineCapacity>::operator=(const Base& other)
+ {
+ other.checkValidity();
+ removeFromIteratorsList();
+
+ m_deque = other.m_deque;
+ m_index = other.m_index;
+ addToIteratorsList();
+ checkValidity();
+ return *this;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::~DequeIteratorBase()
+ {
+#ifndef NDEBUG
+ removeFromIteratorsList();
+ m_deque = 0;
+#endif
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline bool DequeIteratorBase<T, inlineCapacity>::isEqual(const Base& other) const
+ {
+ checkValidity(other);
+ return m_index == other.m_index;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void DequeIteratorBase<T, inlineCapacity>::increment()
+ {
+ checkValidity();
+ ASSERT(m_index != m_deque->m_end);
+ ASSERT(m_deque->m_buffer.capacity());
+ if (m_index == m_deque->m_buffer.capacity() - 1)
+ m_index = 0;
+ else
+ ++m_index;
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void DequeIteratorBase<T, inlineCapacity>::decrement()
+ {
+ checkValidity();
+ ASSERT(m_index != m_deque->m_start);
+ ASSERT(m_deque->m_buffer.capacity());
+ if (!m_index)
+ m_index = m_deque->m_buffer.capacity() - 1;
+ else
+ --m_index;
+ checkValidity();
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline T* DequeIteratorBase<T, inlineCapacity>::after() const
+ {
+ checkValidity();
+ ASSERT(m_index != m_deque->m_end);
+ return &m_deque->m_buffer.buffer()[m_index];
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline T* DequeIteratorBase<T, inlineCapacity>::before() const
+ {
+ checkValidity();
+ ASSERT(m_index != m_deque->m_start);
+ if (!m_index)
+ return &m_deque->m_buffer.buffer()[m_deque->m_buffer.capacity() - 1];
+ return &m_deque->m_buffer.buffer()[m_index - 1];
+ }
+
+} // namespace WTF
+
+using WTF::Deque;
+
+#endif // WTF_Deque_h
diff --git a/Source/JavaScriptCore/wtf/DisallowCType.h b/Source/JavaScriptCore/wtf/DisallowCType.h
new file mode 100644
index 000000000..436f7f214
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DisallowCType.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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 WTF_DisallowCType_h
+#define WTF_DisallowCType_h
+
+// The behavior of many of the functions in the <ctype.h> header is dependent
+// on the current locale. But almost all uses of these functions are for
+// locale-independent, ASCII-specific purposes. In WebKit code we use our own
+// ASCII-specific functions instead. This header makes sure we get a compile-time
+// error if we use one of the <ctype.h> functions by accident.
+
+#include <ctype.h>
+
+#undef isalnum
+#undef isalpha
+#undef isascii
+#undef isblank
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+#undef toascii
+#undef tolower
+#undef toupper
+
+#define isalnum isalnum_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isalpha isalpha_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isascii isascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isblank isblank_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define iscntrl iscntrl_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isdigit isdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isgraph isgraph_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define islower islower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isprint isprint_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define ispunct ispunct_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isspace isspace_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isupper isupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define isxdigit isxdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define toascii toascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define tolower tolower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+#define toupper toupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/DoublyLinkedList.h b/Source/JavaScriptCore/wtf/DoublyLinkedList.h
new file mode 100644
index 000000000..18aa00e17
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DoublyLinkedList.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2011 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 DoublyLinkedList_h
+#define DoublyLinkedList_h
+
+namespace WTF {
+
+// This class allows nodes to share code without dictating data member layout.
+template<typename T> class DoublyLinkedListNode {
+public:
+ DoublyLinkedListNode();
+
+ void setPrev(T*);
+ void setNext(T*);
+
+ T* prev() const;
+ T* next() const;
+};
+
+template<typename T> inline DoublyLinkedListNode<T>::DoublyLinkedListNode()
+{
+ setPrev(0);
+ setNext(0);
+}
+
+template<typename T> inline void DoublyLinkedListNode<T>::setPrev(T* prev)
+{
+ static_cast<T*>(this)->m_prev = prev;
+}
+
+template<typename T> inline void DoublyLinkedListNode<T>::setNext(T* next)
+{
+ static_cast<T*>(this)->m_next = next;
+}
+
+template<typename T> inline T* DoublyLinkedListNode<T>::prev() const
+{
+ return static_cast<const T*>(this)->m_prev;
+}
+
+template<typename T> inline T* DoublyLinkedListNode<T>::next() const
+{
+ return static_cast<const T*>(this)->m_next;
+}
+
+template<typename T> class DoublyLinkedList {
+public:
+ DoublyLinkedList();
+
+ bool isEmpty() const;
+ size_t size() const; // This is O(n).
+ void clear();
+
+ T* head() const;
+ T* removeHead();
+
+ void append(T*);
+ void remove(T*);
+
+private:
+ T* m_head;
+ T* m_tail;
+};
+
+template<typename T> inline DoublyLinkedList<T>::DoublyLinkedList()
+ : m_head(0)
+ , m_tail(0)
+{
+}
+
+template<typename T> inline bool DoublyLinkedList<T>::isEmpty() const
+{
+ return !m_head;
+}
+
+template<typename T> inline size_t DoublyLinkedList<T>::size() const
+{
+ size_t size = 0;
+ for (T* node = m_head; node; node = node->next())
+ ++size;
+ return size;
+}
+
+template<typename T> inline void DoublyLinkedList<T>::clear()
+{
+ m_head = 0;
+ m_tail = 0;
+}
+
+template<typename T> inline T* DoublyLinkedList<T>::head() const
+{
+ return m_head;
+}
+
+template<typename T> inline void DoublyLinkedList<T>::append(T* node)
+{
+ if (!m_tail) {
+ ASSERT(!m_head);
+ m_head = node;
+ m_tail = node;
+ node->setPrev(0);
+ node->setNext(0);
+ return;
+ }
+
+ ASSERT(m_head);
+ m_tail->setNext(node);
+ node->setPrev(m_tail);
+ node->setNext(0);
+ m_tail = node;
+}
+
+template<typename T> inline void DoublyLinkedList<T>::remove(T* node)
+{
+ if (node->prev()) {
+ ASSERT(node != m_head);
+ node->prev()->setNext(node->next());
+ } else {
+ ASSERT(node == m_head);
+ m_head = node->next();
+ }
+
+ if (node->next()) {
+ ASSERT(node != m_tail);
+ node->next()->setPrev(node->prev());
+ } else {
+ ASSERT(node == m_tail);
+ m_tail = node->prev();
+ }
+}
+
+template<typename T> inline T* DoublyLinkedList<T>::removeHead()
+{
+ T* node = head();
+ if (node)
+ remove(node);
+ return node;
+}
+
+} // namespace WTF
+
+using WTF::DoublyLinkedListNode;
+using WTF::DoublyLinkedList;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/DynamicAnnotations.cpp b/Source/JavaScriptCore/wtf/DynamicAnnotations.cpp
new file mode 100644
index 000000000..b662877a5
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DynamicAnnotations.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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.
+ * * 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 "DynamicAnnotations.h"
+
+#if USE(DYNAMIC_ANNOTATIONS) && !USE(DYNAMIC_ANNOTATIONS_NOIMPL)
+
+// Identical code folding(-Wl,--icf=all) countermeasures.
+// This makes all Annotate* functions different, which prevents the linker from
+// folding them.
+#ifdef __COUNTER__
+#define DYNAMIC_ANNOTATIONS_IMPL \
+ volatile short lineno = (__LINE__ << 8) + __COUNTER__; \
+ (void)lineno;
+#else
+#define DYNAMIC_ANNOTATIONS_IMPL \
+ volatile short lineno = (__LINE__ << 8); \
+ (void)lineno;
+#endif
+
+void WTFAnnotateBenignRaceSized(const char*, int, const volatile void*, long, const char*)
+{
+ DYNAMIC_ANNOTATIONS_IMPL
+}
+
+void WTFAnnotateHappensBefore(const char*, int, const volatile void*)
+{
+ DYNAMIC_ANNOTATIONS_IMPL
+}
+
+void WTFAnnotateHappensAfter(const char*, int, const volatile void*)
+{
+ DYNAMIC_ANNOTATIONS_IMPL
+}
+
+#endif // USE(DYNAMIC_ANNOTATIONS) && !USE(DYNAMIC_ANNOTATIONS_NOIMPL)
diff --git a/Source/JavaScriptCore/wtf/DynamicAnnotations.h b/Source/JavaScriptCore/wtf/DynamicAnnotations.h
new file mode 100644
index 000000000..38acce35e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/DynamicAnnotations.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 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.
+ * * 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_DynamicAnnotations_h
+#define WTF_DynamicAnnotations_h
+
+/* This file defines dynamic annotations for use with dynamic analysis
+ * tool such as ThreadSanitizer, Valgrind, etc.
+ *
+ * Dynamic annotation is a source code annotation that affects
+ * the generated code (that is, the annotation is not a comment).
+ * Each such annotation is attached to a particular
+ * instruction and/or to a particular object (address) in the program.
+ *
+ * By using dynamic annotations a developer can give more details to the dynamic
+ * analysis tool to improve its precision.
+ *
+ * In C/C++ program the annotations are represented as C macros.
+ * With the default build flags, these macros are empty, hence don't affect
+ * performance of a compiled binary.
+ * If dynamic annotations are enabled, they just call no-op functions.
+ * The dynamic analysis tools can intercept these functions and replace them
+ * with their own implementations.
+ *
+ * See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations for more information.
+ */
+
+#if USE(DYNAMIC_ANNOTATIONS)
+/* Tell data race detector that we're not interested in reports on the given address range. */
+#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) WTFAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
+#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) WTFAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+/* Annotations for user-defined synchronization mechanisms.
+ * These annotations can be used to define happens-before arcs in user-defined
+ * synchronization mechanisms: the race detector will infer an arc from
+ * the former to the latter when they share the same argument pointer.
+ *
+ * The most common case requiring annotations is atomic reference counting:
+ * bool deref() {
+ * ANNOTATE_HAPPENS_BEFORE(&m_refCount);
+ * if (!atomicDecrement(&m_refCount)) {
+ * // m_refCount is now 0
+ * ANNOTATE_HAPPENS_AFTER(&m_refCount);
+ * // "return true; happens-after each atomicDecrement of m_refCount"
+ * return true;
+ * }
+ * return false;
+ * }
+ */
+#define WTF_ANNOTATE_HAPPENS_BEFORE(address) WTFAnnotateHappensBefore(__FILE__, __LINE__, address)
+#define WTF_ANNOTATE_HAPPENS_AFTER(address) WTFAnnotateHappensAfter(__FILE__, __LINE__, address)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Don't use these directly, use the above macros instead. */
+void WTFAnnotateBenignRaceSized(const char* file, int line, const volatile void* memory, long size, const char* description);
+void WTFAnnotateHappensBefore(const char* file, int line, const volatile void* address);
+void WTFAnnotateHappensAfter(const char* file, int line, const volatile void* address);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#else // USE(DYNAMIC_ANNOTATIONS)
+/* These macros are empty when dynamic annotations are not enabled so you can
+ * use them without affecting the performance of release binaries. */
+#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)
+#define WTF_ANNOTATE_BENIGN_RACE(pointer, description)
+#define WTF_ANNOTATE_HAPPENS_BEFORE(address)
+#define WTF_ANNOTATE_HAPPENS_AFTER(address)
+#endif // USE(DYNAMIC_ANNOTATIONS)
+
+#endif // WTF_DynamicAnnotations_h
diff --git a/Source/JavaScriptCore/wtf/Encoder.h b/Source/JavaScriptCore/wtf/Encoder.h
new file mode 100644
index 000000000..109b0db8d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Encoder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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 Encoder_h
+#define Encoder_h
+
+#include <stdint.h>
+
+namespace WTF {
+
+class String;
+
+class Encoder {
+protected:
+ Encoder() { }
+ virtual ~Encoder() { }
+
+public:
+ virtual void encodeBytes(const uint8_t*, size_t) = 0;
+
+ virtual void encodeBool(bool) = 0;
+ virtual void encodeUInt32(uint32_t) = 0;
+ virtual void encodeUInt64(uint64_t) = 0;
+ virtual void encodeInt32(int32_t) = 0;
+ virtual void encodeInt64(int64_t) = 0;
+ virtual void encodeFloat(float) = 0;
+ virtual void encodeDouble(double) = 0;
+ virtual void encodeString(const String&) = 0;
+};
+
+} // namespace WTF
+
+using WTF::Encoder;
+
+#endif // Encoder_h
diff --git a/Source/JavaScriptCore/wtf/ExportMacros.h b/Source/JavaScriptCore/wtf/ExportMacros.h
new file mode 100644
index 000000000..a6b3bce5a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ExportMacros.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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.
+ *
+ * This file handles shared library symbol export decorations. It is recommended
+ * that all WebKit projects use these definitions so that symbol exports work
+ * properly on all platforms and compilers that WebKit builds under.
+ */
+
+#ifndef ExportMacros_h
+#define ExportMacros_h
+
+#include "Platform.h"
+
+// See note in wtf/Platform.h for more info on EXPORT_MACROS.
+#if USE(EXPORT_MACROS)
+
+#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !COMPILER(GCC)
+#define WTF_EXPORT __declspec(dllexport)
+#define WTF_IMPORT __declspec(dllimport)
+#define WTF_HIDDEN
+#elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__)
+#define WTF_EXPORT __attribute__((visibility("default")))
+#define WTF_IMPORT WTF_EXPORT
+#define WTF_HIDDEN __attribute__((visibility("hidden")))
+#else
+#define WTF_EXPORT
+#define WTF_IMPORT
+#define WTF_HIDDEN
+#endif
+
+// FIXME: When all ports are using the export macros, we should replace
+// WTF_EXPORTDATA with WTF_EXPORT_PRIVATE macros.
+#if defined(BUILDING_WTF)
+#define WTF_EXPORTDATA WTF_EXPORT
+#else
+#define WTF_EXPORTDATA WTF_IMPORT
+#endif
+
+#else // !USE(EXPORT_MACROS)
+
+#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !COMPILER(GCC)
+#if defined(BUILDING_WTF)
+#define WTF_EXPORTDATA __declspec(dllexport)
+#else
+#define WTF_EXPORTDATA __declspec(dllimport)
+#endif
+#else // PLATFORM(CHROMIUM) || !OS(WINDOWS) || COMPILER(GCC)
+#define WTF_EXPORTDATA
+#endif // !PLATFORM(CHROMIUM)...
+
+#define WTF_EXPORTCLASS WTF_EXPORTDATA
+
+#define WTF_EXPORT
+#define WTF_IMPORT
+#define WTF_HIDDEN
+
+#endif // USE(EXPORT_MACROS)
+
+#if defined(BUILDING_WTF)
+#define WTF_EXPORT_PRIVATE WTF_EXPORT
+#else
+#define WTF_EXPORT_PRIVATE WTF_IMPORT
+#endif
+
+#define WTF_EXPORT_HIDDEN WTF_HIDDEN
+
+#define HIDDEN_INLINE WTF_EXPORT_HIDDEN inline
+
+#endif // ExportMacros_h
diff --git a/Source/JavaScriptCore/wtf/FastAllocBase.h b/Source/JavaScriptCore/wtf/FastAllocBase.h
new file mode 100644
index 000000000..1edbed94d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/FastAllocBase.h
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2008, 2009 Paul Pedriana <ppedriana@ea.com>. 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 FastAllocBase_h
+#define FastAllocBase_h
+
+// Provides customizable overrides of fastMalloc/fastFree and operator new/delete
+//
+// Provided functionality:
+// Macro: WTF_MAKE_FAST_ALLOCATED
+// namespace WTF {
+//
+// T* fastNew<T>();
+// T* fastNew<T>(arg);
+// T* fastNew<T>(arg, arg);
+// T* fastNewArray<T>(count);
+// void fastDelete(T* p);
+// void fastDeleteArray(T* p);
+// void fastNonNullDelete(T* p);
+// void fastNonNullDeleteArray(T* p);
+// }
+//
+// FastDelete assumes that the underlying
+//
+// Example usage:
+// class Widget {
+// WTF_MAKE_FAST_ALLOCATED
+// ...
+// };
+//
+// struct Data {
+// WTF_MAKE_FAST_ALLOCATED
+// public:
+// ...
+// };
+//
+// char* charPtr = fastNew<char>();
+// fastDelete(charPtr);
+//
+// char* charArrayPtr = fastNewArray<char>(37);
+// fastDeleteArray(charArrayPtr);
+//
+// void** voidPtrPtr = fastNew<void*>();
+// fastDelete(voidPtrPtr);
+//
+// void** voidPtrArrayPtr = fastNewArray<void*>(37);
+// fastDeleteArray(voidPtrArrayPtr);
+//
+// POD* podPtr = fastNew<POD>();
+// fastDelete(podPtr);
+//
+// POD* podArrayPtr = fastNewArray<POD>(37);
+// fastDeleteArray(podArrayPtr);
+//
+// Object* objectPtr = fastNew<Object>();
+// fastDelete(objectPtr);
+//
+// Object* objectArrayPtr = fastNewArray<Object>(37);
+// fastDeleteArray(objectArrayPtr);
+//
+
+#include <new>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "Assertions.h"
+#include "FastMalloc.h"
+#include "StdLibExtras.h"
+#include "TypeTraits.h"
+
+#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); \
+ } \
+ void* operator new(size_t, NotNullTag, void* location) \
+ { \
+ ASSERT(location); \
+ return location; \
+ } \
+private: \
+typedef int ThisIsHereToForceASemicolonAfterThisMacro
+
+namespace WTF {
+
+ // fastNew / fastDelete
+
+ template <typename T>
+ inline T* fastNew()
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T;
+ }
+
+ template <typename T, typename Arg1>
+ inline T* fastNew(Arg1 arg1)
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T(arg1);
+ }
+
+ template <typename T, typename Arg1, typename Arg2>
+ inline T* fastNew(Arg1 arg1, Arg2 arg2)
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T(arg1, arg2);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T(arg1, arg2, arg3);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T(arg1, arg2, arg3, arg4);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+ inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ {
+ void* p = fastMalloc(sizeof(T));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
+ return ::new (p) T(arg1, arg2, arg3, arg4, arg5);
+ }
+
+ namespace Internal {
+
+ // We define a union of pointer to an integer and pointer to T.
+ // When non-POD arrays are allocated we add a few leading bytes to tell what
+ // the size of the array is. We return to the user the pointer to T.
+ // The way to think of it is as if we allocate a struct like so:
+ // struct Array {
+ // AllocAlignmentInteger m_size;
+ // T m_T[array count];
+ // };
+
+ template <typename T>
+ union ArraySize {
+ AllocAlignmentInteger* size;
+ T* t;
+ };
+
+ // This is a support template for fastNewArray.
+ // This handles the case wherein T has a trivial ctor and a trivial dtor.
+ template <typename T, bool trivialCtor, bool trivialDtor>
+ struct NewArrayImpl {
+ static T* fastNewArray(size_t count)
+ {
+ T* p = static_cast<T*>(fastMalloc(sizeof(T) * count));
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
+ return p;
+ }
+ };
+
+ // This is a support template for fastNewArray.
+ // This handles the case wherein T has a non-trivial ctor and a trivial dtor.
+ template <typename T>
+ struct NewArrayImpl<T, false, true> {
+ static T* fastNewArray(size_t count)
+ {
+ T* p = static_cast<T*>(fastMalloc(sizeof(T) * count));
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
+
+ for (T* pObject = p, *pObjectEnd = pObject + count; pObject != pObjectEnd; ++pObject)
+ ::new (pObject) T;
+
+ return p;
+ }
+ };
+
+ // This is a support template for fastNewArray.
+ // This handles the case wherein T has a trivial ctor and a non-trivial dtor.
+ template <typename T>
+ struct NewArrayImpl<T, true, false> {
+ static T* fastNewArray(size_t count)
+ {
+ void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count));
+ ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) };
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
+ *a.size++ = count;
+ // No need to construct the objects in this case.
+
+ return a.t;
+ }
+ };
+
+ // This is a support template for fastNewArray.
+ // This handles the case wherein T has a non-trivial ctor and a non-trivial dtor.
+ template <typename T>
+ struct NewArrayImpl<T, false, false> {
+ static T* fastNewArray(size_t count)
+ {
+ void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count));
+ ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) };
+
+ if (!p)
+ return 0;
+
+ fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
+ *a.size++ = count;
+
+ for (T* pT = a.t, *pTEnd = pT + count; pT != pTEnd; ++pT)
+ ::new (pT) T;
+
+ return a.t;
+ }
+ };
+ } // namespace Internal
+
+ template <typename T>
+ inline T* fastNewArray(size_t count)
+ {
+ return Internal::NewArrayImpl<T, WTF::HasTrivialConstructor<T>::value, WTF::HasTrivialDestructor<T>::value>::fastNewArray(count);
+ }
+
+ template <typename T>
+ inline void fastDelete(T* p)
+ {
+ if (!p)
+ return;
+
+ fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
+ p->~T();
+ fastFree(p);
+ }
+
+ template <typename T>
+ inline void fastDeleteSkippingDestructor(T* p)
+ {
+ if (!p)
+ return;
+
+ fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
+ fastFree(p);
+ }
+
+ namespace Internal {
+ // This is a support template for fastDeleteArray.
+ // This handles the case wherein T has a trivial dtor.
+ template <typename T, bool trivialDtor>
+ struct DeleteArrayImpl {
+ static void fastDeleteArray(void* p)
+ {
+ // No need to destruct the objects in this case.
+ // We expect that fastFree checks for null.
+ fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray);
+ fastFree(p);
+ }
+ };
+
+ // This is a support template for fastDeleteArray.
+ // This handles the case wherein T has a non-trivial dtor.
+ template <typename T>
+ struct DeleteArrayImpl<T, false> {
+ static void fastDeleteArray(T* p)
+ {
+ if (!p)
+ return;
+
+ ArraySize<T> a;
+ a.t = p;
+ a.size--; // Decrement size pointer
+
+ T* pEnd = p + *a.size;
+ while (pEnd-- != p)
+ pEnd->~T();
+
+ fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray);
+ fastFree(a.size);
+ }
+ };
+
+ } // namespace Internal
+
+ template <typename T>
+ void fastDeleteArray(T* p)
+ {
+ Internal::DeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastDeleteArray(p);
+ }
+
+
+ template <typename T>
+ inline void fastNonNullDelete(T* p)
+ {
+ fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
+ p->~T();
+ fastFree(p);
+ }
+
+ namespace Internal {
+ // This is a support template for fastDeleteArray.
+ // This handles the case wherein T has a trivial dtor.
+ template <typename T, bool trivialDtor>
+ struct NonNullDeleteArrayImpl {
+ static void fastNonNullDeleteArray(void* p)
+ {
+ fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray);
+ // No need to destruct the objects in this case.
+ fastFree(p);
+ }
+ };
+
+ // This is a support template for fastDeleteArray.
+ // This handles the case wherein T has a non-trivial dtor.
+ template <typename T>
+ struct NonNullDeleteArrayImpl<T, false> {
+ static void fastNonNullDeleteArray(T* p)
+ {
+ ArraySize<T> a;
+ a.t = p;
+ a.size--;
+
+ T* pEnd = p + *a.size;
+ while (pEnd-- != p)
+ pEnd->~T();
+
+ fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray);
+ fastFree(a.size);
+ }
+ };
+
+ } // namespace Internal
+
+ template <typename T>
+ void fastNonNullDeleteArray(T* p)
+ {
+ Internal::NonNullDeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastNonNullDeleteArray(p);
+ }
+
+
+} // namespace WTF
+
+using WTF::fastDeleteSkippingDestructor;
+
+#endif // FastAllocBase_h
diff --git a/Source/JavaScriptCore/wtf/FastMalloc.cpp b/Source/JavaScriptCore/wtf/FastMalloc.cpp
new file mode 100644
index 000000000..5c684500f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/FastMalloc.cpp
@@ -0,0 +1,4708 @@
+// Copyright (c) 2005, 2007, Google Inc.
+// All rights reserved.
+// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011 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:
+//
+// * 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.
+
+// ---
+// Author: Sanjay Ghemawat <opensource@google.com>
+//
+// A malloc that uses a per-thread cache to satisfy small malloc requests.
+// (The time for malloc/free of a small object drops from 300 ns to 50 ns.)
+//
+// See doc/tcmalloc.html for a high-level
+// description of how this malloc works.
+//
+// SYNCHRONIZATION
+// 1. The thread-specific lists are accessed without acquiring any locks.
+// This is safe because each such list is only accessed by one thread.
+// 2. We have a lock per central free-list, and hold it while manipulating
+// the central free list for a particular size.
+// 3. The central page allocator is protected by "pageheap_lock".
+// 4. The pagemap (which maps from page-number to descriptor),
+// can be read without holding any locks, and written while holding
+// the "pageheap_lock".
+// 5. To improve performance, a subset of the information one can get
+// from the pagemap is cached in a data structure, pagemap_cache_,
+// that atomically reads and writes its entries. This cache can be
+// read and written without locking.
+//
+// This multi-threaded access to the pagemap is safe for fairly
+// subtle reasons. We basically assume that when an object X is
+// allocated by thread A and deallocated by thread B, there must
+// have been appropriate synchronization in the handoff of object
+// X from thread A to thread B. The same logic applies to pagemap_cache_.
+//
+// THE PAGEID-TO-SIZECLASS CACHE
+// Hot PageID-to-sizeclass mappings are held by pagemap_cache_. If this cache
+// returns 0 for a particular PageID then that means "no information," not that
+// the sizeclass is 0. The cache may have stale information for pages that do
+// not hold the beginning of any free()'able object. Staleness is eliminated
+// in Populate() for pages with sizeclass > 0 objects, and in do_malloc() and
+// do_memalign() for all other relevant pages.
+//
+// TODO: Bias reclamation to larger addresses
+// TODO: implement mallinfo/mallopt
+// TODO: Better testing
+//
+// 9/28/2003 (new page-level allocator replaces ptmalloc2):
+// * malloc/free of small objects goes from ~300 ns to ~50 ns.
+// * allocation of a reasonably complicated struct
+// goes from about 1100 ns to about 300 ns.
+
+#include "config.h"
+#include "FastMalloc.h"
+
+#include "Assertions.h"
+#include <limits>
+#if OS(WINDOWS)
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+#include <wtf/StdLibExtras.h>
+#include <string.h>
+
+#ifndef NO_TCMALLOC_SAMPLES
+#ifdef WTF_CHANGES
+#define NO_TCMALLOC_SAMPLES
+#endif
+#endif
+
+#if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC) && defined(NDEBUG)
+#define FORCE_SYSTEM_MALLOC 0
+#else
+#define FORCE_SYSTEM_MALLOC 1
+#endif
+
+// Use a background thread to periodically scavenge memory to release back to the system
+#if PLATFORM(IOS)
+#define USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY 0
+#else
+#define USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY 1
+#endif
+
+#ifndef NDEBUG
+namespace WTF {
+
+#if OS(WINDOWS)
+
+// TLS_OUT_OF_INDEXES is not defined on WinCE.
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
+
+static DWORD isForibiddenTlsIndex = TLS_OUT_OF_INDEXES;
+static const LPVOID kTlsAllowValue = reinterpret_cast<LPVOID>(0); // Must be zero.
+static const LPVOID kTlsForbiddenValue = reinterpret_cast<LPVOID>(1);
+
+#if !ASSERT_DISABLED
+static bool isForbidden()
+{
+ // By default, fastMalloc is allowed so we don't allocate the
+ // tls index unless we're asked to make it forbidden. If TlsSetValue
+ // has not been called on a thread, the value returned by TlsGetValue is 0.
+ return (isForibiddenTlsIndex != TLS_OUT_OF_INDEXES) && (TlsGetValue(isForibiddenTlsIndex) == kTlsForbiddenValue);
+}
+#endif
+
+void fastMallocForbid()
+{
+ if (isForibiddenTlsIndex == TLS_OUT_OF_INDEXES)
+ isForibiddenTlsIndex = TlsAlloc(); // a little racey, but close enough for debug only
+ TlsSetValue(isForibiddenTlsIndex, kTlsForbiddenValue);
+}
+
+void fastMallocAllow()
+{
+ if (isForibiddenTlsIndex == TLS_OUT_OF_INDEXES)
+ return;
+ TlsSetValue(isForibiddenTlsIndex, kTlsAllowValue);
+}
+
+#else // !OS(WINDOWS)
+
+static pthread_key_t isForbiddenKey;
+static pthread_once_t isForbiddenKeyOnce = PTHREAD_ONCE_INIT;
+static void initializeIsForbiddenKey()
+{
+ pthread_key_create(&isForbiddenKey, 0);
+}
+
+#if !ASSERT_DISABLED
+static bool isForbidden()
+{
+ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey);
+ return !!pthread_getspecific(isForbiddenKey);
+}
+#endif
+
+void fastMallocForbid()
+{
+ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey);
+ pthread_setspecific(isForbiddenKey, &isForbiddenKey);
+}
+
+void fastMallocAllow()
+{
+ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey);
+ pthread_setspecific(isForbiddenKey, 0);
+}
+#endif // OS(WINDOWS)
+
+} // namespace WTF
+#endif // NDEBUG
+
+namespace WTF {
+
+
+namespace Internal {
+#if !ENABLE(WTF_MALLOC_VALIDATION)
+void fastMallocMatchFailed(void*);
+#else
+COMPILE_ASSERT(((sizeof(ValidationHeader) % sizeof(AllocAlignmentInteger)) == 0), ValidationHeader_must_produce_correct_alignment);
+#endif
+
+NO_RETURN_DUE_TO_CRASH void fastMallocMatchFailed(void*)
+{
+ CRASH();
+}
+
+} // namespace Internal
+
+
+void* fastZeroedMalloc(size_t n)
+{
+ void* result = fastMalloc(n);
+ memset(result, 0, n);
+ return result;
+}
+
+char* fastStrDup(const char* src)
+{
+ size_t len = strlen(src) + 1;
+ char* dup = static_cast<char*>(fastMalloc(len));
+ memcpy(dup, src, len);
+ return dup;
+}
+
+TryMallocReturnValue tryFastZeroedMalloc(size_t n)
+{
+ void* result;
+ if (!tryFastMalloc(n).getValue(result))
+ return 0;
+ memset(result, 0, n);
+ return result;
+}
+
+} // namespace WTF
+
+#if FORCE_SYSTEM_MALLOC
+
+#if OS(DARWIN)
+#include <malloc/malloc.h>
+#elif OS(WINDOWS)
+#include <malloc.h>
+#endif
+
+namespace WTF {
+
+TryMallocReturnValue tryFastMalloc(size_t n)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= n) // If overflow would occur...
+ return 0;
+
+ void* result = malloc(n + Internal::ValidationBufferSize);
+ if (!result)
+ return 0;
+ Internal::ValidationHeader* header = static_cast<Internal::ValidationHeader*>(result);
+ header->m_size = n;
+ header->m_type = Internal::AllocTypeMalloc;
+ header->m_prefix = static_cast<unsigned>(Internal::ValidationPrefix);
+ result = header + 1;
+ *Internal::fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
+ return result;
+#else
+ return malloc(n);
+#endif
+}
+
+void* fastMalloc(size_t n)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ TryMallocReturnValue returnValue = tryFastMalloc(n);
+ void* result;
+ if (!returnValue.getValue(result))
+ CRASH();
+#else
+ void* result = malloc(n);
+#endif
+
+ if (!result)
+ CRASH();
+
+ return result;
+}
+
+TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ size_t totalBytes = n_elements * element_size;
+ if (n_elements > 1 && element_size && (totalBytes / element_size) != n_elements)
+ return 0;
+
+ TryMallocReturnValue returnValue = tryFastMalloc(totalBytes);
+ void* result;
+ if (!returnValue.getValue(result))
+ return 0;
+ memset(result, 0, totalBytes);
+ fastMallocValidate(result);
+ return result;
+#else
+ return calloc(n_elements, element_size);
+#endif
+}
+
+void* fastCalloc(size_t n_elements, size_t element_size)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ TryMallocReturnValue returnValue = tryFastCalloc(n_elements, element_size);
+ void* result;
+ if (!returnValue.getValue(result))
+ CRASH();
+#else
+ void* result = calloc(n_elements, element_size);
+#endif
+
+ if (!result)
+ CRASH();
+
+ return result;
+}
+
+void fastFree(void* p)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (!p)
+ return;
+
+ fastMallocMatchValidateFree(p, Internal::AllocTypeMalloc);
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ memset(p, 0xCC, header->m_size);
+ free(header);
+#else
+ free(p);
+#endif
+}
+
+TryMallocReturnValue tryFastRealloc(void* p, size_t n)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (p) {
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= n) // If overflow would occur...
+ return 0;
+ fastMallocValidate(p);
+ Internal::ValidationHeader* result = static_cast<Internal::ValidationHeader*>(realloc(Internal::fastMallocValidationHeader(p), n + Internal::ValidationBufferSize));
+ if (!result)
+ return 0;
+ result->m_size = n;
+ result = result + 1;
+ *fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
+ return result;
+ } else {
+ return fastMalloc(n);
+ }
+#else
+ return realloc(p, n);
+#endif
+}
+
+void* fastRealloc(void* p, size_t n)
+{
+ ASSERT(!isForbidden());
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ TryMallocReturnValue returnValue = tryFastRealloc(p, n);
+ void* result;
+ if (!returnValue.getValue(result))
+ CRASH();
+#else
+ void* result = realloc(p, n);
+#endif
+
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void releaseFastMallocFreeMemory() { }
+
+FastMallocStatistics fastMallocStatistics()
+{
+ FastMallocStatistics statistics = { 0, 0, 0 };
+ return statistics;
+}
+
+size_t fastMallocSize(const void* p)
+{
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ return Internal::fastMallocValidationHeader(const_cast<void*>(p))->m_size;
+#elif OS(DARWIN)
+ return malloc_size(p);
+#elif OS(WINDOWS)
+ return _msize(const_cast<void*>(p));
+#else
+ return 1;
+#endif
+}
+
+} // namespace WTF
+
+#if OS(DARWIN)
+// This symbol is present in the JavaScriptCore exports file even when FastMalloc is disabled.
+// It will never be used in this case, so it's type and value are less interesting than its presence.
+extern "C" const int jscore_fastmalloc_introspection = 0;
+#endif
+
+#else // FORCE_SYSTEM_MALLOC
+
+#if HAVE(STDINT_H)
+#include <stdint.h>
+#elif HAVE(INTTYPES_H)
+#include <inttypes.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include "AlwaysInline.h"
+#include "Assertions.h"
+#include "TCPackedCache.h"
+#include "TCPageMap.h"
+#include "TCSpinLock.h"
+#include "TCSystemAlloc.h"
+#include <algorithm>
+#include <limits>
+#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 OS(WINDOWS)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#ifdef WTF_CHANGES
+
+#if OS(DARWIN)
+#include "MallocZoneSupport.h"
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#endif
+
+#if HAVE(HEADER_DETECTION_H)
+#include "HeaderDetection.h"
+#endif
+
+#if HAVE(DISPATCH_H)
+#include <dispatch/dispatch.h>
+#endif
+
+#if HAVE(PTHREAD_MACHDEP_H)
+#include <System/pthread_machdep.h>
+
+#if defined(__PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0)
+#define WTF_USE_PTHREAD_GETSPECIFIC_DIRECT 1
+#endif
+#endif
+
+#ifndef PRIuS
+#define PRIuS "zu"
+#endif
+
+// Calling pthread_getspecific through a global function pointer is faster than a normal
+// call to the function on Mac OS X, and it's used in performance-critical code. So we
+// use a function pointer. But that's not necessarily faster on other platforms, and we had
+// problems with this technique on Windows, so we'll do this only on Mac OS X.
+#if OS(DARWIN)
+#if !USE(PTHREAD_GETSPECIFIC_DIRECT)
+static void* (*pthread_getspecific_function_pointer)(pthread_key_t) = pthread_getspecific;
+#define pthread_getspecific(key) pthread_getspecific_function_pointer(key)
+#else
+#define pthread_getspecific(key) _pthread_getspecific_direct(key)
+#define pthread_setspecific(key, val) _pthread_setspecific_direct(key, (val))
+#endif
+#endif
+
+#define DEFINE_VARIABLE(type, name, value, meaning) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead { \
+ type FLAGS_##name(value); \
+ char FLAGS_no##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name
+
+#define DEFINE_int64(name, value, meaning) \
+ DEFINE_VARIABLE(int64_t, name, value, meaning)
+
+#define DEFINE_double(name, value, meaning) \
+ DEFINE_VARIABLE(double, name, value, meaning)
+
+namespace WTF {
+
+#define malloc fastMalloc
+#define calloc fastCalloc
+#define free fastFree
+#define realloc fastRealloc
+
+#define MESSAGE LOG_ERROR
+#define CHECK_CONDITION ASSERT
+
+#if OS(DARWIN)
+struct Span;
+class TCMalloc_Central_FreeListPadded;
+class TCMalloc_PageHeap;
+class TCMalloc_ThreadCache;
+template <typename T> class PageHeapAllocator;
+
+class FastMallocZone {
+public:
+ static void init();
+
+ static kern_return_t enumerate(task_t, void*, unsigned typeMmask, vm_address_t zoneAddress, memory_reader_t, vm_range_recorder_t);
+ static size_t goodSize(malloc_zone_t*, size_t size) { return size; }
+ static boolean_t check(malloc_zone_t*) { return true; }
+ static void print(malloc_zone_t*, boolean_t) { }
+ static void log(malloc_zone_t*, void*) { }
+ static void forceLock(malloc_zone_t*) { }
+ static void forceUnlock(malloc_zone_t*) { }
+ static void statistics(malloc_zone_t*, malloc_statistics_t* stats) { memset(stats, 0, sizeof(malloc_statistics_t)); }
+
+private:
+ FastMallocZone(TCMalloc_PageHeap*, TCMalloc_ThreadCache**, TCMalloc_Central_FreeListPadded*, PageHeapAllocator<Span>*, PageHeapAllocator<TCMalloc_ThreadCache>*);
+ static size_t size(malloc_zone_t*, const void*);
+ static void* zoneMalloc(malloc_zone_t*, size_t);
+ static void* zoneCalloc(malloc_zone_t*, size_t numItems, size_t size);
+ static void zoneFree(malloc_zone_t*, void*);
+ static void* zoneRealloc(malloc_zone_t*, void*, size_t);
+ static void* zoneValloc(malloc_zone_t*, size_t) { LOG_ERROR("valloc is not supported"); return 0; }
+ static void zoneDestroy(malloc_zone_t*) { }
+
+ malloc_zone_t m_zone;
+ TCMalloc_PageHeap* m_pageHeap;
+ TCMalloc_ThreadCache** m_threadHeaps;
+ TCMalloc_Central_FreeListPadded* m_centralCaches;
+ PageHeapAllocator<Span>* m_spanAllocator;
+ PageHeapAllocator<TCMalloc_ThreadCache>* m_pageHeapAllocator;
+};
+
+#endif
+
+#endif
+
+#ifndef WTF_CHANGES
+// This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if
+// you're porting to a system where you really can't get a stacktrace.
+#ifdef NO_TCMALLOC_SAMPLES
+// We use #define so code compiles even if you #include stacktrace.h somehow.
+# define GetStackTrace(stack, depth, skip) (0)
+#else
+# include <google/stacktrace.h>
+#endif
+#endif
+
+// Even if we have support for thread-local storage in the compiler
+// and linker, the OS may not support it. We need to check that at
+// runtime. Right now, we have to keep a manual set of "bad" OSes.
+#if defined(HAVE_TLS)
+ static bool kernel_supports_tls = false; // be conservative
+ static inline bool KernelSupportsTLS() {
+ return kernel_supports_tls;
+ }
+# if !HAVE_DECL_UNAME // if too old for uname, probably too old for TLS
+ static void CheckIfKernelSupportsTLS() {
+ kernel_supports_tls = false;
+ }
+# else
+# include <sys/utsname.h> // DECL_UNAME checked for <sys/utsname.h> too
+ static void CheckIfKernelSupportsTLS() {
+ struct utsname buf;
+ if (uname(&buf) != 0) { // should be impossible
+ MESSAGE("uname failed assuming no TLS support (errno=%d)\n", errno);
+ kernel_supports_tls = false;
+ } else if (strcasecmp(buf.sysname, "linux") == 0) {
+ // The linux case: the first kernel to support TLS was 2.6.0
+ if (buf.release[0] < '2' && buf.release[1] == '.') // 0.x or 1.x
+ kernel_supports_tls = false;
+ else if (buf.release[0] == '2' && buf.release[1] == '.' &&
+ buf.release[2] >= '0' && buf.release[2] < '6' &&
+ buf.release[3] == '.') // 2.0 - 2.5
+ kernel_supports_tls = false;
+ else
+ kernel_supports_tls = true;
+ } else { // some other kernel, we'll be optimisitic
+ kernel_supports_tls = true;
+ }
+ // TODO(csilvers): VLOG(1) the tls status once we support RAW_VLOG
+ }
+# endif // HAVE_DECL_UNAME
+#endif // HAVE_TLS
+
+// __THROW is defined in glibc systems. It means, counter-intuitively,
+// "This function will never throw an exception." It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW // I guess we're not on a glibc system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
+//-------------------------------------------------------------------
+// Configuration
+//-------------------------------------------------------------------
+
+// Not all possible combinations of the following parameters make
+// sense. In particular, if kMaxSize increases, you may have to
+// increase kNumClasses as well.
+static const size_t kPageShift = 12;
+static const size_t kPageSize = 1 << kPageShift;
+static const size_t kMaxSize = 8u * kPageSize;
+static const size_t kAlignShift = 3;
+static const size_t kAlignment = 1 << kAlignShift;
+static const size_t kNumClasses = 68;
+
+// Allocates a big block of memory for the pagemap once we reach more than
+// 128MB
+static const size_t kPageMapBigAllocationThreshold = 128 << 20;
+
+// Minimum number of pages to fetch from system at a time. Must be
+// significantly bigger than kPageSize to amortize system-call
+// overhead, and also to reduce external fragementation. Also, we
+// should keep this value big because various incarnations of Linux
+// have small limits on the number of mmap() regions per
+// address-space.
+static const size_t kMinSystemAlloc = 1 << (20 - kPageShift);
+
+// Number of objects to move between a per-thread list and a central
+// list in one shot. We want this to be not too small so we can
+// amortize the lock overhead for accessing the central list. Making
+// it too big may temporarily cause unnecessary memory wastage in the
+// per-thread free list until the scavenger cleans up the list.
+static int num_objects_to_move[kNumClasses];
+
+// Maximum length we allow a per-thread free-list to have before we
+// move objects from it into the corresponding central free-list. We
+// want this big to avoid locking the central free-list too often. It
+// should not hurt to make this list somewhat big because the
+// scavenging code will shrink it down when its contents are not in use.
+static const int kMaxFreeListLength = 256;
+
+// Lower and upper bounds on the per-thread cache sizes
+static const size_t kMinThreadCacheSize = kMaxSize * 2;
+#if PLATFORM(IOS)
+static const size_t kMaxThreadCacheSize = 512 * 1024;
+#else
+static const size_t kMaxThreadCacheSize = 2 << 20;
+#endif
+
+// Default bound on the total amount of thread caches
+static const size_t kDefaultOverallThreadCacheSize = 16 << 20;
+
+// For all span-lengths < kMaxPages we keep an exact-size list.
+// REQUIRED: kMaxPages >= kMinSystemAlloc;
+static const size_t kMaxPages = kMinSystemAlloc;
+
+/* The smallest prime > 2^n */
+static int primes_list[] = {
+ // Small values might cause high rates of sampling
+ // and hence commented out.
+ // 2, 5, 11, 17, 37, 67, 131, 257,
+ // 521, 1031, 2053, 4099, 8209, 16411,
+ 32771, 65537, 131101, 262147, 524309, 1048583,
+ 2097169, 4194319, 8388617, 16777259, 33554467 };
+
+// Twice the approximate gap between sampling actions.
+// I.e., we take one sample approximately once every
+// tcmalloc_sample_parameter/2
+// bytes of allocation, i.e., ~ once every 128KB.
+// Must be a prime number.
+#ifdef NO_TCMALLOC_SAMPLES
+DEFINE_int64(tcmalloc_sample_parameter, 0,
+ "Unused: code is compiled with NO_TCMALLOC_SAMPLES");
+static size_t sample_period = 0;
+#else
+DEFINE_int64(tcmalloc_sample_parameter, 262147,
+ "Twice the approximate gap between sampling actions."
+ " Must be a prime number. Otherwise will be rounded up to a "
+ " larger prime number");
+static size_t sample_period = 262147;
+#endif
+
+// Protects sample_period above
+static SpinLock sample_period_lock = SPINLOCK_INITIALIZER;
+
+// Parameters for controlling how fast memory is returned to the OS.
+
+DEFINE_double(tcmalloc_release_rate, 1,
+ "Rate at which we release unused memory to the system. "
+ "Zero means we never release memory back to the system. "
+ "Increase this flag to return memory faster; decrease it "
+ "to return memory slower. Reasonable rates are in the "
+ "range [0,10]");
+
+//-------------------------------------------------------------------
+// Mapping from size to size_class and vice versa
+//-------------------------------------------------------------------
+
+// Sizes <= 1024 have an alignment >= 8. So for such sizes we have an
+// array indexed by ceil(size/8). Sizes > 1024 have an alignment >= 128.
+// So for these larger sizes we have an array indexed by ceil(size/128).
+//
+// We flatten both logical arrays into one physical array and use
+// arithmetic to compute an appropriate index. The constants used by
+// ClassIndex() were selected to make the flattening work.
+//
+// Examples:
+// Size Expression Index
+// -------------------------------------------------------
+// 0 (0 + 7) / 8 0
+// 1 (1 + 7) / 8 1
+// ...
+// 1024 (1024 + 7) / 8 128
+// 1025 (1025 + 127 + (120<<7)) / 128 129
+// ...
+// 32768 (32768 + 127 + (120<<7)) / 128 376
+static const size_t kMaxSmallSize = 1024;
+static const int shift_amount[2] = { 3, 7 }; // For divides by 8 or 128
+static const int add_amount[2] = { 7, 127 + (120 << 7) };
+static unsigned char class_array[377];
+
+// Compute index of the class_array[] entry for a given size
+static inline int ClassIndex(size_t s) {
+ const int i = (s > kMaxSmallSize);
+ return static_cast<int>((s + add_amount[i]) >> shift_amount[i]);
+}
+
+// Mapping from size class to max size storable in that class
+static size_t class_to_size[kNumClasses];
+
+// Mapping from size class to number of pages to allocate at a time
+static size_t class_to_pages[kNumClasses];
+
+// TransferCache is used to cache transfers of num_objects_to_move[size_class]
+// back and forth between thread caches and the central cache for a given size
+// class.
+struct TCEntry {
+ void *head; // Head of chain of objects.
+ void *tail; // Tail of chain of objects.
+};
+// A central cache freelist can have anywhere from 0 to kNumTransferEntries
+// slots to put link list chains into. To keep memory usage bounded the total
+// number of TCEntries across size classes is fixed. Currently each size
+// class is initially given one TCEntry which also means that the maximum any
+// one class can have is kNumClasses.
+static const int kNumTransferEntries = kNumClasses;
+
+// Note: the following only works for "n"s that fit in 32-bits, but
+// that is fine since we only use it for small sizes.
+static inline int LgFloor(size_t n) {
+ int log = 0;
+ for (int i = 4; i >= 0; --i) {
+ int shift = (1 << i);
+ size_t x = n >> shift;
+ if (x != 0) {
+ n = x;
+ log += shift;
+ }
+ }
+ ASSERT(n == 1);
+ return log;
+}
+
+// Some very basic linked list functions for dealing with using void * as
+// storage.
+
+static inline void *SLL_Next(void *t) {
+ return *(reinterpret_cast<void**>(t));
+}
+
+static inline void SLL_SetNext(void *t, void *n) {
+ *(reinterpret_cast<void**>(t)) = n;
+}
+
+static inline void SLL_Push(void **list, void *element) {
+ SLL_SetNext(element, *list);
+ *list = element;
+}
+
+static inline void *SLL_Pop(void **list) {
+ void *result = *list;
+ *list = SLL_Next(*list);
+ return result;
+}
+
+
+// Remove N elements from a linked list to which head points. head will be
+// modified to point to the new head. start and end will point to the first
+// and last nodes of the range. Note that end will point to NULL after this
+// function is called.
+static inline void SLL_PopRange(void **head, int N, void **start, void **end) {
+ if (N == 0) {
+ *start = NULL;
+ *end = NULL;
+ return;
+ }
+
+ void *tmp = *head;
+ for (int i = 1; i < N; ++i) {
+ tmp = SLL_Next(tmp);
+ }
+
+ *start = *head;
+ *end = tmp;
+ *head = SLL_Next(tmp);
+ // Unlink range from list.
+ SLL_SetNext(tmp, NULL);
+}
+
+static inline void SLL_PushRange(void **head, void *start, void *end) {
+ if (!start) return;
+ SLL_SetNext(end, *head);
+ *head = start;
+}
+
+static inline size_t SLL_Size(void *head) {
+ int count = 0;
+ while (head) {
+ count++;
+ head = SLL_Next(head);
+ }
+ return count;
+}
+
+// Setup helper functions.
+
+static ALWAYS_INLINE size_t SizeClass(size_t size) {
+ return class_array[ClassIndex(size)];
+}
+
+// Get the byte-size for a specified class
+static ALWAYS_INLINE size_t ByteSizeForClass(size_t cl) {
+ return class_to_size[cl];
+}
+static int NumMoveSize(size_t size) {
+ if (size == 0) return 0;
+ // Use approx 64k transfers between thread and central caches.
+ int num = static_cast<int>(64.0 * 1024.0 / size);
+ if (num < 2) num = 2;
+ // Clamp well below kMaxFreeListLength to avoid ping pong between central
+ // and thread caches.
+ if (num > static_cast<int>(0.8 * kMaxFreeListLength))
+ num = static_cast<int>(0.8 * kMaxFreeListLength);
+
+ // Also, avoid bringing in too many objects into small object free
+ // lists. There are lots of such lists, and if we allow each one to
+ // fetch too many at a time, we end up having to scavenge too often
+ // (especially when there are lots of threads and each thread gets a
+ // small allowance for its thread cache).
+ //
+ // TODO: Make thread cache free list sizes dynamic so that we do not
+ // have to equally divide a fixed resource amongst lots of threads.
+ if (num > 32) num = 32;
+
+ return num;
+}
+
+// Initialize the mapping arrays
+static void InitSizeClasses() {
+ // Do some sanity checking on add_amount[]/shift_amount[]/class_array[]
+ if (ClassIndex(0) < 0) {
+ MESSAGE("Invalid class index %d for size 0\n", ClassIndex(0));
+ CRASH();
+ }
+ if (static_cast<size_t>(ClassIndex(kMaxSize)) >= sizeof(class_array)) {
+ MESSAGE("Invalid class index %d for kMaxSize\n", ClassIndex(kMaxSize));
+ CRASH();
+ }
+
+ // Compute the size classes we want to use
+ size_t sc = 1; // Next size class to assign
+ unsigned char alignshift = kAlignShift;
+ int last_lg = -1;
+ for (size_t size = kAlignment; size <= kMaxSize; size += (1 << alignshift)) {
+ int lg = LgFloor(size);
+ if (lg > last_lg) {
+ // Increase alignment every so often.
+ //
+ // Since we double the alignment every time size doubles and
+ // size >= 128, this means that space wasted due to alignment is
+ // at most 16/128 i.e., 12.5%. Plus we cap the alignment at 256
+ // bytes, so the space wasted as a percentage starts falling for
+ // sizes > 2K.
+ if ((lg >= 7) && (alignshift < 8)) {
+ alignshift++;
+ }
+ last_lg = lg;
+ }
+
+ // Allocate enough pages so leftover is less than 1/8 of total.
+ // This bounds wasted space to at most 12.5%.
+ size_t psize = kPageSize;
+ while ((psize % size) > (psize >> 3)) {
+ psize += kPageSize;
+ }
+ const size_t my_pages = psize >> kPageShift;
+
+ if (sc > 1 && my_pages == class_to_pages[sc-1]) {
+ // See if we can merge this into the previous class without
+ // increasing the fragmentation of the previous class.
+ const size_t my_objects = (my_pages << kPageShift) / size;
+ const size_t prev_objects = (class_to_pages[sc-1] << kPageShift)
+ / class_to_size[sc-1];
+ if (my_objects == prev_objects) {
+ // Adjust last class to include this size
+ class_to_size[sc-1] = size;
+ continue;
+ }
+ }
+
+ // Add new class
+ class_to_pages[sc] = my_pages;
+ class_to_size[sc] = size;
+ sc++;
+ }
+ if (sc != kNumClasses) {
+ MESSAGE("wrong number of size classes: found %" PRIuS " instead of %d\n",
+ sc, int(kNumClasses));
+ CRASH();
+ }
+
+ // Initialize the mapping arrays
+ int next_size = 0;
+ for (unsigned char c = 1; c < kNumClasses; c++) {
+ const size_t max_size_in_class = class_to_size[c];
+ for (size_t s = next_size; s <= max_size_in_class; s += kAlignment) {
+ class_array[ClassIndex(s)] = c;
+ }
+ next_size = static_cast<int>(max_size_in_class + kAlignment);
+ }
+
+ // Double-check sizes just to be safe
+ for (size_t size = 0; size <= kMaxSize; size++) {
+ const size_t sc = SizeClass(size);
+ if (sc == 0) {
+ MESSAGE("Bad size class %" PRIuS " for %" PRIuS "\n", sc, size);
+ CRASH();
+ }
+ if (sc > 1 && size <= class_to_size[sc-1]) {
+ MESSAGE("Allocating unnecessarily large class %" PRIuS " for %" PRIuS
+ "\n", sc, size);
+ CRASH();
+ }
+ if (sc >= kNumClasses) {
+ MESSAGE("Bad size class %" PRIuS " for %" PRIuS "\n", sc, size);
+ CRASH();
+ }
+ const size_t s = class_to_size[sc];
+ if (size > s) {
+ MESSAGE("Bad size %" PRIuS " for %" PRIuS " (sc = %" PRIuS ")\n", s, size, sc);
+ CRASH();
+ }
+ if (s == 0) {
+ MESSAGE("Bad size %" PRIuS " for %" PRIuS " (sc = %" PRIuS ")\n", s, size, sc);
+ CRASH();
+ }
+ }
+
+ // Initialize the num_objects_to_move array.
+ for (size_t cl = 1; cl < kNumClasses; ++cl) {
+ num_objects_to_move[cl] = NumMoveSize(ByteSizeForClass(cl));
+ }
+
+#ifndef WTF_CHANGES
+ if (false) {
+ // Dump class sizes and maximum external wastage per size class
+ for (size_t cl = 1; cl < kNumClasses; ++cl) {
+ const int alloc_size = class_to_pages[cl] << kPageShift;
+ const int alloc_objs = alloc_size / class_to_size[cl];
+ const int min_used = (class_to_size[cl-1] + 1) * alloc_objs;
+ const int max_waste = alloc_size - min_used;
+ MESSAGE("SC %3d [ %8d .. %8d ] from %8d ; %2.0f%% maxwaste\n",
+ int(cl),
+ int(class_to_size[cl-1] + 1),
+ int(class_to_size[cl]),
+ int(class_to_pages[cl] << kPageShift),
+ max_waste * 100.0 / alloc_size
+ );
+ }
+ }
+#endif
+}
+
+// -------------------------------------------------------------------------
+// Simple allocator for objects of a specified type. External locking
+// is required before accessing one of these objects.
+// -------------------------------------------------------------------------
+
+// Metadata allocator -- keeps stats about how many bytes allocated
+static uint64_t metadata_system_bytes = 0;
+static void* MetaDataAlloc(size_t bytes) {
+ void* result = TCMalloc_SystemAlloc(bytes, 0);
+ if (result != NULL) {
+ metadata_system_bytes += bytes;
+ }
+ return result;
+}
+
+template <class T>
+class PageHeapAllocator {
+ private:
+ // How much to allocate from system at a time
+ static const size_t kAllocIncrement = 32 << 10;
+
+ // Aligned size of T
+ static const size_t kAlignedSize
+ = (((sizeof(T) + kAlignment - 1) / kAlignment) * kAlignment);
+
+ // Free area from which to carve new objects
+ char* free_area_;
+ size_t free_avail_;
+
+ // Linked list of all regions allocated by this allocator
+ void* allocated_regions_;
+
+ // Free list of already carved objects
+ void* free_list_;
+
+ // Number of allocated but unfreed objects
+ int inuse_;
+
+ public:
+ void Init() {
+ ASSERT(kAlignedSize <= kAllocIncrement);
+ inuse_ = 0;
+ allocated_regions_ = 0;
+ free_area_ = NULL;
+ free_avail_ = 0;
+ free_list_ = NULL;
+ }
+
+ T* New() {
+ // Consult free list
+ void* result;
+ if (free_list_ != NULL) {
+ result = free_list_;
+ free_list_ = *(reinterpret_cast<void**>(result));
+ } else {
+ if (free_avail_ < kAlignedSize) {
+ // Need more room
+ char* new_allocation = reinterpret_cast<char*>(MetaDataAlloc(kAllocIncrement));
+ if (!new_allocation)
+ CRASH();
+
+ *reinterpret_cast_ptr<void**>(new_allocation) = allocated_regions_;
+ allocated_regions_ = new_allocation;
+ free_area_ = new_allocation + kAlignedSize;
+ free_avail_ = kAllocIncrement - kAlignedSize;
+ }
+ result = free_area_;
+ free_area_ += kAlignedSize;
+ free_avail_ -= kAlignedSize;
+ }
+ inuse_++;
+ return reinterpret_cast<T*>(result);
+ }
+
+ void Delete(T* p) {
+ *(reinterpret_cast<void**>(p)) = free_list_;
+ free_list_ = p;
+ inuse_--;
+ }
+
+ int inuse() const { return inuse_; }
+
+#if defined(WTF_CHANGES) && OS(DARWIN)
+ template <class Recorder>
+ void recordAdministrativeRegions(Recorder& recorder, const RemoteMemoryReader& reader)
+ {
+ for (void* adminAllocation = allocated_regions_; adminAllocation; adminAllocation = reader.nextEntryInLinkedList(reinterpret_cast<void**>(adminAllocation)))
+ recorder.recordRegion(reinterpret_cast<vm_address_t>(adminAllocation), kAllocIncrement);
+ }
+#endif
+};
+
+// -------------------------------------------------------------------------
+// Span - a contiguous run of pages
+// -------------------------------------------------------------------------
+
+// Type that can hold a page number
+typedef uintptr_t PageID;
+
+// Type that can hold the length of a run of pages
+typedef uintptr_t Length;
+
+static const Length kMaxValidPages = (~static_cast<Length>(0)) >> kPageShift;
+
+// Convert byte size into pages. This won't overflow, but may return
+// an unreasonably large value if bytes is huge enough.
+static inline Length pages(size_t bytes) {
+ return (bytes >> kPageShift) +
+ ((bytes & (kPageSize - 1)) > 0 ? 1 : 0);
+}
+
+// Convert a user size into the number of bytes that will actually be
+// allocated
+static size_t AllocationSize(size_t bytes) {
+ if (bytes > kMaxSize) {
+ // Large object: we allocate an integral number of pages
+ ASSERT(bytes <= (kMaxValidPages << kPageShift));
+ return pages(bytes) << kPageShift;
+ } else {
+ // Small object: find the size class to which it belongs
+ return ByteSizeForClass(SizeClass(bytes));
+ }
+}
+
+// Information kept for a span (a contiguous run of pages).
+struct Span {
+ PageID start; // Starting page number
+ Length length; // Number of pages in span
+ Span* next; // Used when in link list
+ Span* prev; // Used when in link list
+ void* objects; // Linked list of free objects
+ unsigned int free : 1; // Is the span free
+#ifndef NO_TCMALLOC_SAMPLES
+ unsigned int sample : 1; // Sampled object?
+#endif
+ unsigned int sizeclass : 8; // Size-class for small objects (or 0)
+ unsigned int refcount : 11; // Number of non-free objects
+ bool decommitted : 1;
+
+#undef SPAN_HISTORY
+#ifdef SPAN_HISTORY
+ // For debugging, we can keep a log events per span
+ int nexthistory;
+ char history[64];
+ int value[64];
+#endif
+};
+
+#define ASSERT_SPAN_COMMITTED(span) ASSERT(!span->decommitted)
+
+#ifdef SPAN_HISTORY
+void Event(Span* span, char op, int v = 0) {
+ span->history[span->nexthistory] = op;
+ span->value[span->nexthistory] = v;
+ span->nexthistory++;
+ if (span->nexthistory == sizeof(span->history)) span->nexthistory = 0;
+}
+#else
+#define Event(s,o,v) ((void) 0)
+#endif
+
+// Allocator/deallocator for spans
+static PageHeapAllocator<Span> span_allocator;
+static Span* NewSpan(PageID p, Length len) {
+ Span* result = span_allocator.New();
+ memset(result, 0, sizeof(*result));
+ result->start = p;
+ result->length = len;
+#ifdef SPAN_HISTORY
+ result->nexthistory = 0;
+#endif
+ return result;
+}
+
+static inline void DeleteSpan(Span* span) {
+#ifndef NDEBUG
+ // In debug mode, trash the contents of deleted Spans
+ memset(span, 0x3f, sizeof(*span));
+#endif
+ span_allocator.Delete(span);
+}
+
+// -------------------------------------------------------------------------
+// Doubly linked list of spans.
+// -------------------------------------------------------------------------
+
+static inline void DLL_Init(Span* list) {
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void DLL_Remove(Span* span) {
+ span->prev->next = span->next;
+ span->next->prev = span->prev;
+ span->prev = NULL;
+ span->next = NULL;
+}
+
+static ALWAYS_INLINE bool DLL_IsEmpty(const Span* list) {
+ return list->next == list;
+}
+
+static int DLL_Length(const Span* list) {
+ int result = 0;
+ for (Span* s = list->next; s != list; s = s->next) {
+ result++;
+ }
+ return result;
+}
+
+#if 0 /* Not needed at the moment -- causes compiler warnings if not used */
+static void DLL_Print(const char* label, const Span* list) {
+ MESSAGE("%-10s %p:", label, list);
+ for (const Span* s = list->next; s != list; s = s->next) {
+ MESSAGE(" <%p,%u,%u>", s, s->start, s->length);
+ }
+ MESSAGE("\n");
+}
+#endif
+
+static inline void DLL_Prepend(Span* list, Span* span) {
+ ASSERT(span->next == NULL);
+ ASSERT(span->prev == NULL);
+ span->next = list->next;
+ span->prev = list;
+ list->next->prev = span;
+ list->next = span;
+}
+
+// -------------------------------------------------------------------------
+// Stack traces kept for sampled allocations
+// The following state is protected by pageheap_lock_.
+// -------------------------------------------------------------------------
+
+// size/depth are made the same size as a pointer so that some generic
+// code below can conveniently cast them back and forth to void*.
+static const int kMaxStackDepth = 31;
+struct StackTrace {
+ uintptr_t size; // Size of object
+ uintptr_t depth; // Number of PC values stored in array below
+ void* stack[kMaxStackDepth];
+};
+static PageHeapAllocator<StackTrace> stacktrace_allocator;
+static Span sampled_objects;
+
+// -------------------------------------------------------------------------
+// Map from page-id to per-page data
+// -------------------------------------------------------------------------
+
+// We use PageMap2<> for 32-bit and PageMap3<> for 64-bit machines.
+// We also use a simple one-level cache for hot PageID-to-sizeclass mappings,
+// because sometimes the sizeclass is all the information we need.
+
+// Selector class -- general selector uses 3-level map
+template <int BITS> class MapSelector {
+ public:
+ typedef TCMalloc_PageMap3<BITS-kPageShift> Type;
+ typedef PackedCache<BITS, uint64_t> CacheType;
+};
+
+#if defined(WTF_CHANGES)
+#if CPU(X86_64)
+// On all known X86-64 platforms, the upper 16 bits are always unused and therefore
+// can be excluded from the PageMap key.
+// See http://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details
+
+static const size_t kBitsUnusedOn64Bit = 16;
+#else
+static const size_t kBitsUnusedOn64Bit = 0;
+#endif
+
+// A three-level map for 64-bit machines
+template <> class MapSelector<64> {
+ public:
+ typedef TCMalloc_PageMap3<64 - kPageShift - kBitsUnusedOn64Bit> Type;
+ typedef PackedCache<64, uint64_t> CacheType;
+};
+#endif
+
+// A two-level map for 32-bit machines
+template <> class MapSelector<32> {
+ public:
+ typedef TCMalloc_PageMap2<32 - kPageShift> Type;
+ typedef PackedCache<32 - kPageShift, uint16_t> CacheType;
+};
+
+// -------------------------------------------------------------------------
+// Page-level allocator
+// * Eager coalescing
+//
+// Heap for page-level allocation. We allow allocating and freeing a
+// contiguous runs of pages (called a "span").
+// -------------------------------------------------------------------------
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+// 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
+
+static SpinLock pageheap_lock = SPINLOCK_INITIALIZER;
+
+class TCMalloc_PageHeap {
+ public:
+ void init();
+
+ // Allocate a run of "n" pages. Returns zero if out of memory.
+ Span* New(Length n);
+
+ // Delete the span "[p, p+n-1]".
+ // REQUIRES: span was returned by earlier call to New() and
+ // has not yet been deleted.
+ void Delete(Span* span);
+
+ // Mark an allocated span as being used for small objects of the
+ // specified size-class.
+ // REQUIRES: span was returned by an earlier call to New()
+ // and has not yet been deleted.
+ void RegisterSizeClass(Span* span, size_t sc);
+
+ // Split an allocated span into two spans: one of length "n" pages
+ // followed by another span of length "span->length - n" pages.
+ // Modifies "*span" to point to the first span of length "n" pages.
+ // Returns a pointer to the second span.
+ //
+ // REQUIRES: "0 < n < span->length"
+ // REQUIRES: !span->free
+ // REQUIRES: span->sizeclass == 0
+ Span* Split(Span* span, Length n);
+
+ // Return the descriptor for the specified page.
+ inline Span* GetDescriptor(PageID p) const {
+ return reinterpret_cast<Span*>(pagemap_.get(p));
+ }
+
+#ifdef WTF_CHANGES
+ inline Span* GetDescriptorEnsureSafe(PageID p)
+ {
+ pagemap_.Ensure(p, 1);
+ return GetDescriptor(p);
+ }
+
+ size_t ReturnedBytes() const;
+#endif
+
+ // Dump state to stderr
+#ifndef WTF_CHANGES
+ void Dump(TCMalloc_Printer* out);
+#endif
+
+ // Return number of bytes allocated from system
+ inline uint64_t SystemBytes() const { return system_bytes_; }
+
+ // Return number of free bytes in heap
+ uint64_t FreeBytes() const {
+ return (static_cast<uint64_t>(free_pages_) << kPageShift);
+ }
+
+ bool Check();
+ size_t CheckList(Span* list, Length min_pages, Length max_pages, bool decommitted);
+
+ // Release all pages on the free list for reuse by the OS:
+ void ReleaseFreePages();
+ void ReleaseFreeList(Span*, Span*);
+
+ // Return 0 if we have no information, or else the correct sizeclass for p.
+ // Reads and writes to pagemap_cache_ do not require locking.
+ // The entries are 64 bits on 64-bit hardware and 16 bits on
+ // 32-bit hardware, and we don't mind raciness as long as each read of
+ // an entry yields a valid entry, not a partially updated entry.
+ size_t GetSizeClassIfCached(PageID p) const {
+ return pagemap_cache_.GetOrDefault(p, 0);
+ }
+ void CacheSizeClass(PageID p, size_t cl) const { pagemap_cache_.Put(p, cl); }
+
+ private:
+ // Pick the appropriate map and cache types based on pointer size
+ typedef MapSelector<8*sizeof(uintptr_t)>::Type PageMap;
+ typedef MapSelector<8*sizeof(uintptr_t)>::CacheType PageMapCache;
+ PageMap pagemap_;
+ mutable PageMapCache pagemap_cache_;
+
+ // We segregate spans of a given size into two circular linked
+ // lists: one for normal spans, and one for spans whose memory
+ // has been returned to the system.
+ struct SpanList {
+ Span normal;
+ Span returned;
+ };
+
+ // List of free spans of length >= kMaxPages
+ SpanList large_;
+
+ // Array mapping from span length to a doubly linked list of free spans
+ SpanList free_[kMaxPages];
+
+ // Number of pages kept in free lists
+ uintptr_t free_pages_;
+
+ // Bytes allocated from system
+ uint64_t system_bytes_;
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ // Number of pages kept in free lists that are still committed.
+ Length free_committed_pages_;
+
+ // 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);
+
+ // REQUIRES span->length >= n
+ // Remove span from its free list, and move any leftover part of
+ // span into appropriate free lists. Also update "span" to have
+ // length exactly "n" and mark it as non-free so it can be returned
+ // to the client.
+ //
+ // "released" is true iff "span" was found on a "returned" list.
+ void Carve(Span* span, Length n, bool released);
+
+ void RecordSpan(Span* span) {
+ pagemap_.set(span->start, span);
+ if (span->length > 1) {
+ pagemap_.set(span->start + span->length - 1, span);
+ }
+ }
+
+ // Allocate a large span of length == n. If successful, returns a
+ // span of exactly the specified length. Else, returns NULL.
+ Span* AllocLarge(Length n);
+
+#if !USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ // Incrementally release some memory to the system.
+ // IncrementalScavenge(n) is called whenever n pages are freed.
+ void IncrementalScavenge(Length n);
+#endif
+
+ // Number of pages to deallocate before doing more scavenging
+ int64_t scavenge_counter_;
+
+ // Index of last free list we scavenged
+ size_t scavenge_index_;
+
+#if defined(WTF_CHANGES) && OS(DARWIN)
+ friend class FastMallocZone;
+#endif
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ void initializeScavenger();
+ ALWAYS_INLINE void signalScavenger();
+ void scavenge();
+ ALWAYS_INLINE bool shouldScavenge() const;
+
+#if HAVE(DISPATCH_H) || OS(WINDOWS)
+ void periodicScavenge();
+ ALWAYS_INLINE bool isScavengerSuspended();
+ ALWAYS_INLINE void scheduleScavenger();
+ ALWAYS_INLINE void rescheduleScavenger();
+ ALWAYS_INLINE void suspendScavenger();
+#endif
+
+#if HAVE(DISPATCH_H)
+ dispatch_queue_t m_scavengeQueue;
+ dispatch_source_t m_scavengeTimer;
+ bool m_scavengingSuspended;
+#elif OS(WINDOWS)
+ static void CALLBACK scavengerTimerFired(void*, BOOLEAN);
+ HANDLE m_scavengeQueueTimer;
+#else
+ static NO_RETURN_WITH_VALUE void* runScavengerThread(void*);
+ NO_RETURN void scavengerThread();
+
+ // 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;
+
+ pthread_mutex_t m_scavengeMutex;
+ pthread_cond_t m_scavengeCondition;
+#endif
+
+#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+};
+
+void TCMalloc_PageHeap::init()
+{
+ pagemap_.init(MetaDataAlloc);
+ pagemap_cache_ = PageMapCache(0);
+ free_pages_ = 0;
+ system_bytes_ = 0;
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ free_committed_pages_ = 0;
+ min_free_committed_pages_since_last_scavenge_ = 0;
+#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+
+ scavenge_counter_ = 0;
+ // Start scavenging at kMaxPages list
+ scavenge_index_ = kMaxPages-1;
+ COMPILE_ASSERT(kNumClasses <= (1 << PageMapCache::kValuebits), valuebits);
+ DLL_Init(&large_.normal);
+ DLL_Init(&large_.returned);
+ for (size_t i = 0; i < kMaxPages; i++) {
+ DLL_Init(&free_[i].normal);
+ DLL_Init(&free_[i].returned);
+ }
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ initializeScavenger();
+#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+}
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+
+#if HAVE(DISPATCH_H)
+
+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, 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_scavengingSuspended = true;
+}
+
+ALWAYS_INLINE bool TCMalloc_PageHeap::isScavengerSuspended()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ return m_scavengingSuspended;
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::scheduleScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ m_scavengingSuspended = false;
+ dispatch_resume(m_scavengeTimer);
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::rescheduleScavenger()
+{
+ // Nothing to do here for libdispatch.
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::suspendScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ m_scavengingSuspended = true;
+ dispatch_suspend(m_scavengeTimer);
+}
+
+#elif OS(WINDOWS)
+
+void TCMalloc_PageHeap::scavengerTimerFired(void* context, BOOLEAN)
+{
+ static_cast<TCMalloc_PageHeap*>(context)->periodicScavenge();
+}
+
+void TCMalloc_PageHeap::initializeScavenger()
+{
+ m_scavengeQueueTimer = 0;
+}
+
+ALWAYS_INLINE bool TCMalloc_PageHeap::isScavengerSuspended()
+{
+ ASSERT(IsHeld(pageheap_lock));
+ return !m_scavengeQueueTimer;
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::scheduleScavenger()
+{
+ // We need to use WT_EXECUTEONLYONCE here and reschedule the timer, because
+ // Windows will fire the timer event even when the function is already running.
+ ASSERT(IsHeld(pageheap_lock));
+ CreateTimerQueueTimer(&m_scavengeQueueTimer, 0, scavengerTimerFired, this, kScavengeDelayInSeconds * 1000, 0, WT_EXECUTEONLYONCE);
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::rescheduleScavenger()
+{
+ // We must delete the timer and create it again, because it is not possible to retrigger a timer on Windows.
+ suspendScavenger();
+ scheduleScavenger();
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::suspendScavenger()
+{
+ ASSERT(IsHeld(pageheap_lock));
+ HANDLE scavengeQueueTimer = m_scavengeQueueTimer;
+ m_scavengeQueueTimer = 0;
+ DeleteTimerQueueTimer(0, scavengeQueueTimer, 0);
+}
+
+#else
+
+void TCMalloc_PageHeap::initializeScavenger()
+{
+ // 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)
+{
+ static_cast<TCMalloc_PageHeap*>(context)->scavengerThread();
+#if (COMPILER(MSVC) || COMPILER(SUNCC))
+ // Without this, Visual Studio and Sun Studio will complain that this method does not return a value.
+ return 0;
+#endif
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+{
+ // m_scavengeMutex should be held before accessing m_scavengeThreadActive.
+ ASSERT(pthread_mutex_trylock(m_scavengeMutex));
+ if (!m_scavengeThreadActive && shouldScavenge())
+ pthread_cond_signal(&m_scavengeCondition);
+}
+
+#endif
+
+void TCMalloc_PageHeap::scavenge()
+{
+ size_t pagesToRelease = min_free_committed_pages_since_last_scavenge_ * kScavengePercentage;
+ size_t targetPageCount = std::max<size_t>(kMinimumFreeCommittedPageCount, free_committed_pages_ - pagesToRelease);
+
+ Length lastFreeCommittedPages = free_committed_pages_;
+ while (free_committed_pages_ > targetPageCount) {
+ ASSERT(Check());
+ 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);
+ }
+ }
+
+ if (lastFreeCommittedPages == free_committed_pages_)
+ break;
+ lastFreeCommittedPages = free_committed_pages_;
+ }
+
+ min_free_committed_pages_since_last_scavenge_ = free_committed_pages_;
+}
+
+ALWAYS_INLINE bool TCMalloc_PageHeap::shouldScavenge() const
+{
+ return free_committed_pages_ > kMinimumFreeCommittedPageCount;
+}
+
+#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+
+inline Span* TCMalloc_PageHeap::New(Length n) {
+ ASSERT(Check());
+ ASSERT(n > 0);
+
+ // Find first size >= n that has a non-empty list
+ for (Length s = n; s < kMaxPages; s++) {
+ Span* ll = NULL;
+ bool released = false;
+ if (!DLL_IsEmpty(&free_[s].normal)) {
+ // Found normal span
+ ll = &free_[s].normal;
+ } else if (!DLL_IsEmpty(&free_[s].returned)) {
+ // Found returned span; reallocate it
+ ll = &free_[s].returned;
+ released = true;
+ } else {
+ // Keep looking in larger classes
+ continue;
+ }
+
+ Span* result = ll->next;
+ Carve(result, n, released);
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ // 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;
+ return result;
+ }
+
+ Span* result = AllocLarge(n);
+ if (result != NULL) {
+ ASSERT_SPAN_COMMITTED(result);
+ return result;
+ }
+
+ // Grow the heap and try again
+ if (!GrowHeap(n)) {
+ ASSERT(Check());
+ return NULL;
+ }
+
+ return AllocLarge(n);
+}
+
+Span* TCMalloc_PageHeap::AllocLarge(Length n) {
+ // find the best span (closest to n in size).
+ // The following loops implements address-ordered best-fit.
+ bool from_released = false;
+ Span *best = NULL;
+
+ // Search through normal list
+ for (Span* span = large_.normal.next;
+ span != &large_.normal;
+ span = span->next) {
+ if (span->length >= n) {
+ if ((best == NULL)
+ || (span->length < best->length)
+ || ((span->length == best->length) && (span->start < best->start))) {
+ best = span;
+ from_released = false;
+ }
+ }
+ }
+
+ // Search through released list in case it has a better fit
+ for (Span* span = large_.returned.next;
+ span != &large_.returned;
+ span = span->next) {
+ if (span->length >= n) {
+ if ((best == NULL)
+ || (span->length < best->length)
+ || ((span->length == best->length) && (span->start < best->start))) {
+ best = span;
+ from_released = true;
+ }
+ }
+ }
+
+ if (best != NULL) {
+ Carve(best, n, from_released);
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ // 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;
+ return best;
+ }
+ return NULL;
+}
+
+Span* TCMalloc_PageHeap::Split(Span* span, Length n) {
+ ASSERT(0 < n);
+ ASSERT(n < span->length);
+ ASSERT(!span->free);
+ ASSERT(span->sizeclass == 0);
+ Event(span, 'T', n);
+
+ const Length extra = span->length - n;
+ Span* leftover = NewSpan(span->start + n, extra);
+ Event(leftover, 'U', extra);
+ RecordSpan(leftover);
+ pagemap_.set(span->start + n - 1, span); // Update map from pageid to span
+ span->length = n;
+
+ return leftover;
+}
+
+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;
+ 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 = &listpair->normal;
+ DLL_Prepend(dst, leftover);
+
+ span->length = n;
+ pagemap_.set(span->start + n - 1, span);
+ }
+}
+
+static ALWAYS_INLINE void mergeDecommittedStates(Span* destination, Span* other)
+{
+ if (destination->decommitted && !other->decommitted) {
+ TCMalloc_SystemRelease(reinterpret_cast<void*>(other->start << kPageShift),
+ static_cast<size_t>(other->length << kPageShift));
+ } else if (other->decommitted && !destination->decommitted) {
+ TCMalloc_SystemRelease(reinterpret_cast<void*>(destination->start << kPageShift),
+ static_cast<size_t>(destination->length << kPageShift));
+ destination->decommitted = true;
+ }
+}
+
+inline void TCMalloc_PageHeap::Delete(Span* span) {
+ ASSERT(Check());
+ ASSERT(!span->free);
+ ASSERT(span->length > 0);
+ ASSERT(GetDescriptor(span->start) == span);
+ ASSERT(GetDescriptor(span->start + span->length - 1) == span);
+ span->sizeclass = 0;
+#ifndef NO_TCMALLOC_SAMPLES
+ span->sample = 0;
+#endif
+
+ // Coalesce -- we guarantee that "p" != 0, so no bounds checking
+ // necessary. We do not bother resetting the stale pagemap
+ // entries for the pieces we are merging together because we only
+ // care about the pagemap entries for the boundaries.
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ // Track the total size of the neighboring free spans that are committed.
+ Length neighboringCommittedSpansLength = 0;
+#endif
+ const PageID p = span->start;
+ const Length n = span->length;
+ Span* prev = GetDescriptor(p-1);
+ if (prev != NULL && prev->free) {
+ // Merge preceding span into this span
+ ASSERT(prev->start + prev->length == p);
+ const Length len = prev->length;
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ if (!prev->decommitted)
+ neighboringCommittedSpansLength += len;
+#endif
+ mergeDecommittedStates(span, prev);
+ DLL_Remove(prev);
+ DeleteSpan(prev);
+ span->start -= len;
+ span->length += len;
+ pagemap_.set(span->start, span);
+ Event(span, 'L', len);
+ }
+ Span* next = GetDescriptor(p+n);
+ if (next != NULL && next->free) {
+ // Merge next span into this span
+ ASSERT(next->start == p+n);
+ const Length len = next->length;
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ if (!next->decommitted)
+ neighboringCommittedSpansLength += len;
+#endif
+ mergeDecommittedStates(span, next);
+ DLL_Remove(next);
+ DeleteSpan(next);
+ span->length += len;
+ pagemap_.set(span->start + span->length - 1, span);
+ Event(span, 'R', len);
+ }
+
+ Event(span, 'D', span->length);
+ span->free = 1;
+ if (span->decommitted) {
+ if (span->length < kMaxPages)
+ DLL_Prepend(&free_[span->length].returned, span);
+ else
+ DLL_Prepend(&large_.returned, span);
+ } else {
+ if (span->length < kMaxPages)
+ DLL_Prepend(&free_[span->length].normal, span);
+ else
+ DLL_Prepend(&large_.normal, span);
+ }
+ free_pages_ += n;
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ if (span->decommitted) {
+ // 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;
+ }
+
+ // Make sure the scavenge thread becomes active if we have enough freed pages to release some back to the system.
+ signalScavenger();
+#else
+ IncrementalScavenge(n);
+#endif
+
+ ASSERT(Check());
+}
+
+#if !USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+void TCMalloc_PageHeap::IncrementalScavenge(Length n) {
+ // Fast path; not yet time to release memory
+ scavenge_counter_ -= n;
+ if (scavenge_counter_ >= 0) return; // Not yet time to scavenge
+
+#if PLATFORM(IOS)
+ static const size_t kDefaultReleaseDelay = 64;
+#else
+ // If there is nothing to release, wait for so many pages before
+ // scavenging again. With 4K pages, this comes to 16MB of memory.
+ static const size_t kDefaultReleaseDelay = 1 << 8;
+#endif
+
+ // Find index of free list to scavenge
+ size_t index = scavenge_index_ + 1;
+ for (size_t i = 0; i < kMaxPages+1; i++) {
+ if (index > kMaxPages) index = 0;
+ SpanList* slist = (index == kMaxPages) ? &large_ : &free_[index];
+ if (!DLL_IsEmpty(&slist->normal)) {
+ // Release the last span on the normal portion of this list
+ Span* s = slist->normal.prev;
+ DLL_Remove(s);
+ TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
+ static_cast<size_t>(s->length << kPageShift));
+ s->decommitted = true;
+ DLL_Prepend(&slist->returned, s);
+
+#if PLATFORM(IOS)
+ scavenge_counter_ = std::max<size_t>(16UL, std::min<size_t>(kDefaultReleaseDelay, kDefaultReleaseDelay - (free_pages_ / kDefaultReleaseDelay)));
+#else
+ scavenge_counter_ = std::max<size_t>(64UL, std::min<size_t>(kDefaultReleaseDelay, kDefaultReleaseDelay - (free_pages_ / kDefaultReleaseDelay)));
+#endif
+
+ if (index == kMaxPages && !DLL_IsEmpty(&slist->normal))
+ scavenge_index_ = index - 1;
+ else
+ scavenge_index_ = index;
+ return;
+ }
+ index++;
+ }
+
+ // Nothing to scavenge, delay for a while
+ scavenge_counter_ = kDefaultReleaseDelay;
+}
+#endif
+
+void TCMalloc_PageHeap::RegisterSizeClass(Span* span, size_t sc) {
+ // Associate span object with all interior pages as well
+ ASSERT(!span->free);
+ ASSERT(GetDescriptor(span->start) == span);
+ ASSERT(GetDescriptor(span->start+span->length-1) == span);
+ Event(span, 'C', sc);
+ span->sizeclass = static_cast<unsigned int>(sc);
+ for (Length i = 1; i < span->length-1; i++) {
+ pagemap_.set(span->start+i, span);
+ }
+}
+
+#ifdef WTF_CHANGES
+size_t TCMalloc_PageHeap::ReturnedBytes() const {
+ size_t result = 0;
+ for (unsigned s = 0; s < kMaxPages; s++) {
+ const int r_length = DLL_Length(&free_[s].returned);
+ unsigned r_pages = s * r_length;
+ result += r_pages << kPageShift;
+ }
+
+ for (Span* s = large_.returned.next; s != &large_.returned; s = s->next)
+ result += s->length << kPageShift;
+ return result;
+}
+#endif
+
+#ifndef WTF_CHANGES
+static double PagesToMB(uint64_t pages) {
+ return (pages << kPageShift) / 1048576.0;
+}
+
+void TCMalloc_PageHeap::Dump(TCMalloc_Printer* out) {
+ int nonempty_sizes = 0;
+ for (int s = 0; s < kMaxPages; s++) {
+ if (!DLL_IsEmpty(&free_[s].normal) || !DLL_IsEmpty(&free_[s].returned)) {
+ nonempty_sizes++;
+ }
+ }
+ out->printf("------------------------------------------------\n");
+ out->printf("PageHeap: %d sizes; %6.1f MB free\n",
+ nonempty_sizes, PagesToMB(free_pages_));
+ out->printf("------------------------------------------------\n");
+ uint64_t total_normal = 0;
+ uint64_t total_returned = 0;
+ for (int s = 0; s < kMaxPages; s++) {
+ const int n_length = DLL_Length(&free_[s].normal);
+ const int r_length = DLL_Length(&free_[s].returned);
+ if (n_length + r_length > 0) {
+ uint64_t n_pages = s * n_length;
+ uint64_t r_pages = s * r_length;
+ total_normal += n_pages;
+ total_returned += r_pages;
+ out->printf("%6u pages * %6u spans ~ %6.1f MB; %6.1f MB cum"
+ "; unmapped: %6.1f MB; %6.1f MB cum\n",
+ s,
+ (n_length + r_length),
+ PagesToMB(n_pages + r_pages),
+ PagesToMB(total_normal + total_returned),
+ PagesToMB(r_pages),
+ PagesToMB(total_returned));
+ }
+ }
+
+ uint64_t n_pages = 0;
+ uint64_t r_pages = 0;
+ int n_spans = 0;
+ int r_spans = 0;
+ out->printf("Normal large spans:\n");
+ for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) {
+ out->printf(" [ %6" PRIuS " pages ] %6.1f MB\n",
+ s->length, PagesToMB(s->length));
+ n_pages += s->length;
+ n_spans++;
+ }
+ out->printf("Unmapped large spans:\n");
+ for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) {
+ out->printf(" [ %6" PRIuS " pages ] %6.1f MB\n",
+ s->length, PagesToMB(s->length));
+ r_pages += s->length;
+ r_spans++;
+ }
+ total_normal += n_pages;
+ total_returned += r_pages;
+ out->printf(">255 large * %6u spans ~ %6.1f MB; %6.1f MB cum"
+ "; unmapped: %6.1f MB; %6.1f MB cum\n",
+ (n_spans + r_spans),
+ PagesToMB(n_pages + r_pages),
+ PagesToMB(total_normal + total_returned),
+ PagesToMB(r_pages),
+ PagesToMB(total_returned));
+}
+#endif
+
+bool TCMalloc_PageHeap::GrowHeap(Length n) {
+ ASSERT(kMaxPages >= kMinSystemAlloc);
+ if (n > kMaxValidPages) return false;
+ Length ask = (n>kMinSystemAlloc) ? n : static_cast<Length>(kMinSystemAlloc);
+ size_t actual_size;
+ void* ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
+ if (ptr == NULL) {
+ if (n < ask) {
+ // Try growing just "n" pages
+ ask = n;
+ ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);
+ }
+ if (ptr == NULL) return false;
+ }
+ ask = actual_size >> kPageShift;
+
+ uint64_t old_system_bytes = system_bytes_;
+ system_bytes_ += (ask << kPageShift);
+ const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ ASSERT(p > 0);
+
+ // If we have already a lot of pages allocated, just pre allocate a bunch of
+ // memory for the page map. This prevents fragmentation by pagemap metadata
+ // when a program keeps allocating and freeing large blocks.
+
+ if (old_system_bytes < kPageMapBigAllocationThreshold
+ && system_bytes_ >= kPageMapBigAllocationThreshold) {
+ pagemap_.PreallocateMoreMemory();
+ }
+
+ // Make sure pagemap_ has entries for all of the new pages.
+ // Plus ensure one before and one after so coalescing code
+ // does not need bounds-checking.
+ if (pagemap_.Ensure(p-1, ask+2)) {
+ // Pretend the new area is allocated and then Delete() it to
+ // cause any necessary coalescing to occur.
+ //
+ // We do not adjust free_pages_ here since Delete() will do it for us.
+ Span* span = NewSpan(p, ask);
+ RecordSpan(span);
+ Delete(span);
+ ASSERT(Check());
+ return true;
+ } else {
+ // We could not allocate memory within "pagemap_"
+ // TODO: Once we can return memory to the system, return the new span
+ return false;
+ }
+}
+
+bool TCMalloc_PageHeap::Check() {
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ size_t totalFreeCommitted = 0;
+#endif
+ ASSERT(free_[0].normal.next == &free_[0].normal);
+ ASSERT(free_[0].returned.next == &free_[0].returned);
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ totalFreeCommitted = CheckList(&large_.normal, kMaxPages, 1000000000, false);
+#else
+ CheckList(&large_.normal, kMaxPages, 1000000000, false);
+#endif
+ CheckList(&large_.returned, kMaxPages, 1000000000, true);
+ for (Length s = 1; s < kMaxPages; s++) {
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ totalFreeCommitted += CheckList(&free_[s].normal, s, s, false);
+#else
+ CheckList(&free_[s].normal, s, s, false);
+#endif
+ CheckList(&free_[s].returned, s, s, true);
+ }
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ ASSERT(totalFreeCommitted == free_committed_pages_);
+#endif
+ return true;
+}
+
+#if ASSERT_DISABLED
+size_t TCMalloc_PageHeap::CheckList(Span*, Length, Length, bool) {
+ return 0;
+}
+#else
+size_t TCMalloc_PageHeap::CheckList(Span* list, Length min_pages, Length max_pages, bool decommitted) {
+ size_t freeCount = 0;
+ for (Span* s = list->next; s != list; s = s->next) {
+ CHECK_CONDITION(s->free);
+ CHECK_CONDITION(s->length >= min_pages);
+ CHECK_CONDITION(s->length <= max_pages);
+ CHECK_CONDITION(GetDescriptor(s->start) == s);
+ CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s);
+ CHECK_CONDITION(s->decommitted == decommitted);
+ freeCount += s->length;
+ }
+ return freeCount;
+}
+#endif
+
+void TCMalloc_PageHeap::ReleaseFreeList(Span* list, Span* returned) {
+ // Walk backwards through list so that when we push these
+ // spans on the "returned" list, we preserve the order.
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ size_t freePageReduction = 0;
+#endif
+
+ while (!DLL_IsEmpty(list)) {
+ Span* s = list->prev;
+
+ DLL_Remove(s);
+ s->decommitted = true;
+ DLL_Prepend(returned, s);
+ TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
+ static_cast<size_t>(s->length << kPageShift));
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ freePageReduction += s->length;
+#endif
+ }
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+ free_committed_pages_ -= freePageReduction;
+ if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_)
+ min_free_committed_pages_since_last_scavenge_ = free_committed_pages_;
+#endif
+}
+
+void TCMalloc_PageHeap::ReleaseFreePages() {
+ for (Length s = 0; s < kMaxPages; s++) {
+ ReleaseFreeList(&free_[s].normal, &free_[s].returned);
+ }
+ ReleaseFreeList(&large_.normal, &large_.returned);
+ ASSERT(Check());
+}
+
+//-------------------------------------------------------------------
+// Free list
+//-------------------------------------------------------------------
+
+class TCMalloc_ThreadCache_FreeList {
+ private:
+ void* list_; // Linked list of nodes
+ uint16_t length_; // Current length
+ uint16_t lowater_; // Low water mark for list length
+
+ public:
+ void Init() {
+ list_ = NULL;
+ length_ = 0;
+ lowater_ = 0;
+ }
+
+ // Return current length of list
+ int length() const {
+ return length_;
+ }
+
+ // Is list empty?
+ bool empty() const {
+ return list_ == NULL;
+ }
+
+ // Low-water mark management
+ int lowwatermark() const { return lowater_; }
+ void clear_lowwatermark() { lowater_ = length_; }
+
+ ALWAYS_INLINE void Push(void* ptr) {
+ SLL_Push(&list_, ptr);
+ length_++;
+ }
+
+ void PushRange(int N, void *start, void *end) {
+ SLL_PushRange(&list_, start, end);
+ length_ = length_ + static_cast<uint16_t>(N);
+ }
+
+ void PopRange(int N, void **start, void **end) {
+ SLL_PopRange(&list_, N, start, end);
+ ASSERT(length_ >= N);
+ length_ = length_ - static_cast<uint16_t>(N);
+ if (length_ < lowater_) lowater_ = length_;
+ }
+
+ ALWAYS_INLINE void* Pop() {
+ ASSERT(list_ != NULL);
+ length_--;
+ if (length_ < lowater_) lowater_ = length_;
+ return SLL_Pop(&list_);
+ }
+
+#ifdef WTF_CHANGES
+ template <class Finder, class Reader>
+ void enumerateFreeObjects(Finder& finder, const Reader& reader)
+ {
+ for (void* nextObject = list_; nextObject; nextObject = reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
+ finder.visit(nextObject);
+ }
+#endif
+};
+
+//-------------------------------------------------------------------
+// Data kept per thread
+//-------------------------------------------------------------------
+
+class TCMalloc_ThreadCache {
+ private:
+ typedef TCMalloc_ThreadCache_FreeList FreeList;
+#if OS(WINDOWS)
+ typedef DWORD ThreadIdentifier;
+#else
+ typedef pthread_t ThreadIdentifier;
+#endif
+
+ size_t size_; // Combined size of data
+ ThreadIdentifier tid_; // Which thread owns it
+ bool in_setspecific_; // Called pthread_setspecific?
+ FreeList list_[kNumClasses]; // Array indexed by size-class
+
+ // We sample allocations, biased by the size of the allocation
+ uint32_t rnd_; // Cheap random number generator
+ size_t bytes_until_sample_; // Bytes until we sample next
+
+ // Allocate a new heap. REQUIRES: pageheap_lock is held.
+ static inline TCMalloc_ThreadCache* NewHeap(ThreadIdentifier tid);
+
+ // Use only as pthread thread-specific destructor function.
+ static void DestroyThreadCache(void* ptr);
+ public:
+ // All ThreadCache objects are kept in a linked list (for stats collection)
+ TCMalloc_ThreadCache* next_;
+ TCMalloc_ThreadCache* prev_;
+
+ void Init(ThreadIdentifier tid);
+ void Cleanup();
+
+ // Accessors (mostly just for printing stats)
+ int freelist_length(size_t cl) const { return list_[cl].length(); }
+
+ // Total byte size in cache
+ size_t Size() const { return size_; }
+
+ ALWAYS_INLINE void* Allocate(size_t size);
+ void Deallocate(void* ptr, size_t size_class);
+
+ ALWAYS_INLINE void FetchFromCentralCache(size_t cl, size_t allocationSize);
+ void ReleaseToCentralCache(size_t cl, int N);
+ void Scavenge();
+ void Print() const;
+
+ // Record allocation of "k" bytes. Return true iff allocation
+ // should be sampled
+ bool SampleAllocation(size_t k);
+
+ // Pick next sampling point
+ void PickNextSample(size_t k);
+
+ static void InitModule();
+ static void InitTSD();
+ static TCMalloc_ThreadCache* GetThreadHeap();
+ static TCMalloc_ThreadCache* GetCache();
+ static TCMalloc_ThreadCache* GetCacheIfPresent();
+ static TCMalloc_ThreadCache* CreateCacheIfNecessary();
+ static void DeleteCache(TCMalloc_ThreadCache* heap);
+ static void BecomeIdle();
+ static void RecomputeThreadCacheSize();
+
+#ifdef WTF_CHANGES
+ template <class Finder, class Reader>
+ void enumerateFreeObjects(Finder& finder, const Reader& reader)
+ {
+ for (unsigned sizeClass = 0; sizeClass < kNumClasses; sizeClass++)
+ list_[sizeClass].enumerateFreeObjects(finder, reader);
+ }
+#endif
+};
+
+//-------------------------------------------------------------------
+// Data kept per size-class in central cache
+//-------------------------------------------------------------------
+
+class TCMalloc_Central_FreeList {
+ public:
+ void Init(size_t cl);
+
+ // These methods all do internal locking.
+
+ // Insert the specified range into the central freelist. N is the number of
+ // elements in the range.
+ void InsertRange(void *start, void *end, int N);
+
+ // Returns the actual number of fetched elements into N.
+ void RemoveRange(void **start, void **end, int *N);
+
+ // Returns the number of free objects in cache.
+ size_t length() {
+ SpinLockHolder h(&lock_);
+ return counter_;
+ }
+
+ // Returns the number of free objects in the transfer cache.
+ int tc_length() {
+ SpinLockHolder h(&lock_);
+ return used_slots_ * num_objects_to_move[size_class_];
+ }
+
+#ifdef WTF_CHANGES
+ template <class Finder, class Reader>
+ void enumerateFreeObjects(Finder& finder, const Reader& reader, TCMalloc_Central_FreeList* remoteCentralFreeList)
+ {
+ for (Span* span = &empty_; span && span != &empty_; span = (span->next ? reader(span->next) : 0))
+ ASSERT(!span->objects);
+
+ ASSERT(!nonempty_.objects);
+ static const ptrdiff_t nonemptyOffset = reinterpret_cast<const char*>(&nonempty_) - reinterpret_cast<const char*>(this);
+
+ Span* remoteNonempty = reinterpret_cast<Span*>(reinterpret_cast<char*>(remoteCentralFreeList) + nonemptyOffset);
+ Span* remoteSpan = nonempty_.next;
+
+ for (Span* span = reader(remoteSpan); span && remoteSpan != remoteNonempty; remoteSpan = span->next, span = (span->next ? reader(span->next) : 0)) {
+ for (void* nextObject = span->objects; nextObject; nextObject = reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
+ finder.visit(nextObject);
+ }
+ }
+#endif
+
+ private:
+ // REQUIRES: lock_ is held
+ // Remove object from cache and return.
+ // Return NULL if no free entries in cache.
+ void* FetchFromSpans();
+
+ // REQUIRES: lock_ is held
+ // Remove object from cache and return. Fetches
+ // from pageheap if cache is empty. Only returns
+ // NULL on allocation failure.
+ void* FetchFromSpansSafe();
+
+ // REQUIRES: lock_ is held
+ // Release a linked list of objects to spans.
+ // May temporarily release lock_.
+ void ReleaseListToSpans(void *start);
+
+ // REQUIRES: lock_ is held
+ // Release an object to spans.
+ // May temporarily release lock_.
+ ALWAYS_INLINE void ReleaseToSpans(void* object);
+
+ // REQUIRES: lock_ is held
+ // Populate cache by fetching from the page heap.
+ // May temporarily release lock_.
+ ALWAYS_INLINE void Populate();
+
+ // REQUIRES: lock is held.
+ // Tries to make room for a TCEntry. If the cache is full it will try to
+ // expand it at the cost of some other cache size. Return false if there is
+ // no space.
+ bool MakeCacheSpace();
+
+ // REQUIRES: lock_ for locked_size_class is held.
+ // Picks a "random" size class to steal TCEntry slot from. In reality it
+ // just iterates over the sizeclasses but does so without taking a lock.
+ // Returns true on success.
+ // May temporarily lock a "random" size class.
+ 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
+ // spans if it allows it to shrink the cache. Return false if it failed to
+ // shrink the cache. Decrements cache_size_ on succeess.
+ // May temporarily take lock_. If it takes lock_, the locked_size_class
+ // lock is released to the thread from holding two size class locks
+ // concurrently which could lead to a deadlock.
+ bool ShrinkCache(int locked_size_class, bool force);
+
+ // This lock protects all the data members. cached_entries and cache_size_
+ // may be looked at without holding the lock.
+ SpinLock lock_;
+
+ // We keep linked lists of empty and non-empty spans.
+ size_t size_class_; // My size class
+ Span empty_; // Dummy header for list of empty spans
+ Span nonempty_; // Dummy header for list of non-empty spans
+ size_t counter_; // Number of free objects in cache entry
+
+ // Here we reserve space for TCEntry cache slots. Since one size class can
+ // end up getting all the TCEntries quota in the system we just preallocate
+ // sufficient number of entries here.
+ TCEntry tc_slots_[kNumTransferEntries];
+
+ // Number of currently used cached entries in tc_slots_. This variable is
+ // updated under a lock but can be read without one.
+ int32_t used_slots_;
+ // The current number of slots for this size class. This is an
+ // adaptive value that is increased if there is lots of traffic
+ // on a given size class.
+ int32_t cache_size_;
+};
+
+// Pad each CentralCache object to multiple of 64 bytes
+class TCMalloc_Central_FreeListPadded : public TCMalloc_Central_FreeList {
+ private:
+ char pad_[(64 - (sizeof(TCMalloc_Central_FreeList) % 64)) % 64];
+};
+
+//-------------------------------------------------------------------
+// Global variables
+//-------------------------------------------------------------------
+
+// Central cache -- a collection of free-lists, one per size-class.
+// We have a separate lock per free-list to reduce contention.
+static TCMalloc_Central_FreeListPadded central_cache[kNumClasses];
+
+// Page-level allocator
+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
+// of pageheap_memory.
+typedef union {
+ void* m_memory;
+ TCMalloc_PageHeap* m_pageHeap;
+} PageHeapUnion;
+
+static inline TCMalloc_PageHeap* getPageHeap()
+{
+ PageHeapUnion u = { &pageheap_memory[0] };
+ return u.m_pageHeap;
+}
+
+#define pageheap getPageHeap()
+
+#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
+
+#if HAVE(DISPATCH_H) || OS(WINDOWS)
+
+void TCMalloc_PageHeap::periodicScavenge()
+{
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->scavenge();
+
+ if (shouldScavenge()) {
+ rescheduleScavenger();
+ return;
+ }
+
+ suspendScavenger();
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ if (isScavengerSuspended() && shouldScavenge())
+ scheduleScavenger();
+}
+
+#else
+
+void TCMalloc_PageHeap::scavengerThread()
+{
+#if HAVE(PTHREAD_SETNAME_NP)
+ pthread_setname_np("JavaScriptCore: FastMalloc scavenger");
+#endif
+
+ while (1) {
+ if (!shouldScavenge()) {
+ pthread_mutex_lock(&m_scavengeMutex);
+ m_scavengeThreadActive = false;
+ // 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(kScavengeDelayInSeconds);
+ {
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->scavenge();
+ }
+ }
+}
+
+#endif
+
+#endif
+
+// If TLS is available, we also store a copy
+// of the per-thread object in a __thread variable
+// since __thread variables are faster to read
+// than pthread_getspecific(). We still need
+// pthread_setspecific() because __thread
+// variables provide no way to run cleanup
+// code when a thread is destroyed.
+#ifdef HAVE_TLS
+static __thread TCMalloc_ThreadCache *threadlocal_heap;
+#endif
+// Thread-specific key. Initialization here is somewhat tricky
+// because some Linux startup code invokes malloc() before it
+// is in a good enough state to handle pthread_keycreate().
+// Therefore, we use TSD keys only after tsd_inited is set to true.
+// Until then, we use a slow path to get the heap object.
+static bool tsd_inited = false;
+#if USE(PTHREAD_GETSPECIFIC_DIRECT)
+static const pthread_key_t heap_key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
+#else
+static pthread_key_t heap_key;
+#endif
+#if OS(WINDOWS)
+DWORD tlsIndex = TLS_OUT_OF_INDEXES;
+#endif
+
+static ALWAYS_INLINE void setThreadHeap(TCMalloc_ThreadCache* heap)
+{
+#if USE(PTHREAD_GETSPECIFIC_DIRECT)
+ // Can't have two libraries both doing this in the same process,
+ // so check and make this crash right away.
+ if (pthread_getspecific(heap_key))
+ CRASH();
+#endif
+
+ // Still do pthread_setspecific even if there's an alternate form
+ // of thread-local storage in use, to benefit from the delete callback.
+ pthread_setspecific(heap_key, heap);
+
+#if OS(WINDOWS)
+ TlsSetValue(tlsIndex, heap);
+#endif
+}
+
+// Allocator for thread heaps
+static PageHeapAllocator<TCMalloc_ThreadCache> threadheap_allocator;
+
+// Linked list of heap objects. Protected by pageheap_lock.
+static TCMalloc_ThreadCache* thread_heaps = NULL;
+static int thread_heap_count = 0;
+
+// Overall thread cache size. Protected by pageheap_lock.
+static size_t overall_thread_cache_size = kDefaultOverallThreadCacheSize;
+
+// Global per-thread cache size. Writes are protected by
+// pageheap_lock. Reads are done without any locking, which should be
+// fine as long as size_t can be written atomically and we don't place
+// invariants between this variable and other pieces of state.
+static volatile size_t per_thread_cache_size = kMaxThreadCacheSize;
+
+//-------------------------------------------------------------------
+// Central cache implementation
+//-------------------------------------------------------------------
+
+void TCMalloc_Central_FreeList::Init(size_t cl) {
+ lock_.Init();
+ size_class_ = cl;
+ DLL_Init(&empty_);
+ DLL_Init(&nonempty_);
+ counter_ = 0;
+
+ cache_size_ = 1;
+ used_slots_ = 0;
+ ASSERT(cache_size_ <= kNumTransferEntries);
+}
+
+void TCMalloc_Central_FreeList::ReleaseListToSpans(void* start) {
+ while (start) {
+ void *next = SLL_Next(start);
+ ReleaseToSpans(start);
+ start = next;
+ }
+}
+
+ALWAYS_INLINE void TCMalloc_Central_FreeList::ReleaseToSpans(void* object) {
+ const PageID p = reinterpret_cast<uintptr_t>(object) >> kPageShift;
+ Span* span = pageheap->GetDescriptor(p);
+ ASSERT(span != NULL);
+ ASSERT(span->refcount > 0);
+
+ // If span is empty, move it to non-empty list
+ if (span->objects == NULL) {
+ DLL_Remove(span);
+ DLL_Prepend(&nonempty_, span);
+ Event(span, 'N', 0);
+ }
+
+ // The following check is expensive, so it is disabled by default
+ if (false) {
+ // Check that object does not occur in list
+ unsigned got = 0;
+ for (void* p = span->objects; p != NULL; p = *((void**) p)) {
+ ASSERT(p != object);
+ got++;
+ }
+ ASSERT(got + span->refcount ==
+ (span->length<<kPageShift)/ByteSizeForClass(span->sizeclass));
+ }
+
+ counter_++;
+ span->refcount--;
+ if (span->refcount == 0) {
+ Event(span, '#', 0);
+ counter_ -= (span->length<<kPageShift) / ByteSizeForClass(span->sizeclass);
+ DLL_Remove(span);
+
+ // Release central list lock while operating on pageheap
+ lock_.Unlock();
+ {
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->Delete(span);
+ }
+ lock_.Lock();
+ } else {
+ *(reinterpret_cast<void**>(object)) = span->objects;
+ span->objects = object;
+ }
+}
+
+ALWAYS_INLINE bool TCMalloc_Central_FreeList::EvictRandomSizeClass(
+ size_t locked_size_class, bool force) {
+ static int race_counter = 0;
+ int t = race_counter++; // Updated without a lock, but who cares.
+ if (t >= static_cast<int>(kNumClasses)) {
+ while (t >= static_cast<int>(kNumClasses)) {
+ t -= kNumClasses;
+ }
+ race_counter = t;
+ }
+ ASSERT(t >= 0);
+ ASSERT(t < static_cast<int>(kNumClasses));
+ if (t == static_cast<int>(locked_size_class)) return false;
+ return central_cache[t].ShrinkCache(static_cast<int>(locked_size_class), force);
+}
+
+bool TCMalloc_Central_FreeList::MakeCacheSpace() {
+ // Is there room in the cache?
+ if (used_slots_ < cache_size_) return true;
+ // Check if we can expand this cache?
+ if (cache_size_ == kNumTransferEntries) return false;
+ // Ok, we'll try to grab an entry from some other size class.
+ if (EvictRandomSizeClass(size_class_, false) ||
+ EvictRandomSizeClass(size_class_, true)) {
+ // Succeeded in evicting, we're going to make our cache larger.
+ cache_size_++;
+ return true;
+ }
+ return false;
+}
+
+
+namespace {
+class LockInverter {
+ private:
+ SpinLock *held_, *temp_;
+ public:
+ inline explicit LockInverter(SpinLock* held, SpinLock *temp)
+ : held_(held), temp_(temp) { held_->Unlock(); temp_->Lock(); }
+ inline ~LockInverter() { temp_->Unlock(); held_->Lock(); }
+};
+}
+
+bool TCMalloc_Central_FreeList::ShrinkCache(int locked_size_class, bool force) {
+ // Start with a quick check without taking a lock.
+ if (cache_size_ == 0) return false;
+ // We don't evict from a full cache unless we are 'forcing'.
+ if (force == false && used_slots_ == cache_size_) return false;
+
+ // Grab lock, but first release the other lock held by this thread. We use
+ // the lock inverter to ensure that we never hold two size class locks
+ // concurrently. That can create a deadlock because there is no well
+ // defined nesting order.
+ LockInverter li(&central_cache[locked_size_class].lock_, &lock_);
+ ASSERT(used_slots_ <= cache_size_);
+ ASSERT(0 <= cache_size_);
+ if (cache_size_ == 0) return false;
+ if (used_slots_ == cache_size_) {
+ if (force == false) return false;
+ // ReleaseListToSpans releases the lock, so we have to make all the
+ // updates to the central list before calling it.
+ cache_size_--;
+ used_slots_--;
+ ReleaseListToSpans(tc_slots_[used_slots_].head);
+ return true;
+ }
+ cache_size_--;
+ return true;
+}
+
+void TCMalloc_Central_FreeList::InsertRange(void *start, void *end, int N) {
+ SpinLockHolder h(&lock_);
+ if (N == num_objects_to_move[size_class_] &&
+ MakeCacheSpace()) {
+ int slot = used_slots_++;
+ ASSERT(slot >=0);
+ ASSERT(slot < kNumTransferEntries);
+ TCEntry *entry = &tc_slots_[slot];
+ entry->head = start;
+ entry->tail = end;
+ return;
+ }
+ ReleaseListToSpans(start);
+}
+
+void TCMalloc_Central_FreeList::RemoveRange(void **start, void **end, int *N) {
+ int num = *N;
+ ASSERT(num > 0);
+
+ SpinLockHolder h(&lock_);
+ if (num == num_objects_to_move[size_class_] && used_slots_ > 0) {
+ int slot = --used_slots_;
+ ASSERT(slot >= 0);
+ TCEntry *entry = &tc_slots_[slot];
+ *start = entry->head;
+ *end = entry->tail;
+ return;
+ }
+
+ // TODO: Prefetch multiple TCEntries?
+ void *tail = FetchFromSpansSafe();
+ if (!tail) {
+ // We are completely out of memory.
+ *start = *end = NULL;
+ *N = 0;
+ return;
+ }
+
+ SLL_SetNext(tail, NULL);
+ void *head = tail;
+ int count = 1;
+ while (count < num) {
+ void *t = FetchFromSpans();
+ if (!t) break;
+ SLL_Push(&head, t);
+ count++;
+ }
+ *start = head;
+ *end = tail;
+ *N = count;
+}
+
+
+void* TCMalloc_Central_FreeList::FetchFromSpansSafe() {
+ void *t = FetchFromSpans();
+ if (!t) {
+ Populate();
+ t = FetchFromSpans();
+ }
+ return t;
+}
+
+void* TCMalloc_Central_FreeList::FetchFromSpans() {
+ if (DLL_IsEmpty(&nonempty_)) return NULL;
+ Span* span = nonempty_.next;
+
+ ASSERT(span->objects != NULL);
+ ASSERT_SPAN_COMMITTED(span);
+ span->refcount++;
+ void* result = span->objects;
+ span->objects = *(reinterpret_cast<void**>(result));
+ if (span->objects == NULL) {
+ // Move to empty list
+ DLL_Remove(span);
+ DLL_Prepend(&empty_, span);
+ Event(span, 'E', 0);
+ }
+ counter_--;
+ return result;
+}
+
+// Fetch memory from the system and add to the central cache freelist.
+ALWAYS_INLINE void TCMalloc_Central_FreeList::Populate() {
+ // Release central list lock while operating on pageheap
+ lock_.Unlock();
+ const size_t npages = class_to_pages[size_class_];
+
+ Span* span;
+ {
+ SpinLockHolder h(&pageheap_lock);
+ span = pageheap->New(npages);
+ 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;
+ }
+ ASSERT_SPAN_COMMITTED(span);
+ ASSERT(span->length == npages);
+ // Cache sizeclass info eagerly. Locking is not necessary.
+ // (Instead of being eager, we could just replace any stale info
+ // about this span, but that seems to be no better in practice.)
+ for (size_t i = 0; i < npages; i++) {
+ pageheap->CacheSizeClass(span->start + i, size_class_);
+ }
+
+ // Split the block into pieces and add to the free-list
+ // TODO: coloring of objects to avoid cache conflicts?
+ void** tail = &span->objects;
+ char* ptr = reinterpret_cast<char*>(span->start << kPageShift);
+ char* limit = ptr + (npages << kPageShift);
+ const size_t size = ByteSizeForClass(size_class_);
+ int num = 0;
+ char* nptr;
+ while ((nptr = ptr + size) <= limit) {
+ *tail = ptr;
+ tail = reinterpret_cast_ptr<void**>(ptr);
+ ptr = nptr;
+ num++;
+ }
+ ASSERT(ptr <= limit);
+ *tail = NULL;
+ span->refcount = 0; // No sub-object in use yet
+
+ // Add span to list of non-empty spans
+ lock_.Lock();
+ DLL_Prepend(&nonempty_, span);
+ counter_ += num;
+}
+
+//-------------------------------------------------------------------
+// TCMalloc_ThreadCache implementation
+//-------------------------------------------------------------------
+
+inline bool TCMalloc_ThreadCache::SampleAllocation(size_t k) {
+ if (bytes_until_sample_ < k) {
+ PickNextSample(k);
+ return true;
+ } else {
+ bytes_until_sample_ -= k;
+ return false;
+ }
+}
+
+void TCMalloc_ThreadCache::Init(ThreadIdentifier tid) {
+ size_ = 0;
+ next_ = NULL;
+ prev_ = NULL;
+ tid_ = tid;
+ in_setspecific_ = false;
+ for (size_t cl = 0; cl < kNumClasses; ++cl) {
+ list_[cl].Init();
+ }
+
+ // Initialize RNG -- run it for a bit to get to good values
+ bytes_until_sample_ = 0;
+ rnd_ = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(this));
+ for (int i = 0; i < 100; i++) {
+ PickNextSample(static_cast<size_t>(FLAGS_tcmalloc_sample_parameter * 2));
+ }
+}
+
+void TCMalloc_ThreadCache::Cleanup() {
+ // Put unused memory back into central cache
+ for (size_t cl = 0; cl < kNumClasses; ++cl) {
+ if (list_[cl].length() > 0) {
+ ReleaseToCentralCache(cl, list_[cl].length());
+ }
+ }
+}
+
+ALWAYS_INLINE void* TCMalloc_ThreadCache::Allocate(size_t size) {
+ ASSERT(size <= kMaxSize);
+ const size_t cl = SizeClass(size);
+ FreeList* list = &list_[cl];
+ size_t allocationSize = ByteSizeForClass(cl);
+ if (list->empty()) {
+ FetchFromCentralCache(cl, allocationSize);
+ if (list->empty()) return NULL;
+ }
+ size_ -= allocationSize;
+ return list->Pop();
+}
+
+inline void TCMalloc_ThreadCache::Deallocate(void* ptr, size_t cl) {
+ size_ += ByteSizeForClass(cl);
+ FreeList* list = &list_[cl];
+ list->Push(ptr);
+ // If enough data is free, put back into central cache
+ if (list->length() > kMaxFreeListLength) {
+ ReleaseToCentralCache(cl, num_objects_to_move[cl]);
+ }
+ if (size_ >= per_thread_cache_size) Scavenge();
+}
+
+// Remove some objects of class "cl" from central cache and add to thread heap
+ALWAYS_INLINE void TCMalloc_ThreadCache::FetchFromCentralCache(size_t cl, size_t allocationSize) {
+ int fetch_count = num_objects_to_move[cl];
+ void *start, *end;
+ central_cache[cl].RemoveRange(&start, &end, &fetch_count);
+ list_[cl].PushRange(fetch_count, start, end);
+ size_ += allocationSize * fetch_count;
+}
+
+// Remove some objects of class "cl" from thread heap and add to central cache
+inline void TCMalloc_ThreadCache::ReleaseToCentralCache(size_t cl, int N) {
+ ASSERT(N > 0);
+ FreeList* src = &list_[cl];
+ if (N > src->length()) N = src->length();
+ size_ -= N*ByteSizeForClass(cl);
+
+ // We return prepackaged chains of the correct size to the central cache.
+ // TODO: Use the same format internally in the thread caches?
+ int batch_size = num_objects_to_move[cl];
+ while (N > batch_size) {
+ void *tail, *head;
+ src->PopRange(batch_size, &head, &tail);
+ central_cache[cl].InsertRange(head, tail, batch_size);
+ N -= batch_size;
+ }
+ void *tail, *head;
+ src->PopRange(N, &head, &tail);
+ central_cache[cl].InsertRange(head, tail, N);
+}
+
+// Release idle memory to the central cache
+inline void TCMalloc_ThreadCache::Scavenge() {
+ // If the low-water mark for the free list is L, it means we would
+ // not have had to allocate anything from the central cache even if
+ // we had reduced the free list size by L. We aim to get closer to
+ // that situation by dropping L/2 nodes from the free list. This
+ // may not release much memory, but if so we will call scavenge again
+ // pretty soon and the low-water marks will be high on that call.
+ //int64 start = CycleClock::Now();
+
+ for (size_t cl = 0; cl < kNumClasses; cl++) {
+ FreeList* list = &list_[cl];
+ const int lowmark = list->lowwatermark();
+ if (lowmark > 0) {
+ const int drop = (lowmark > 1) ? lowmark/2 : 1;
+ ReleaseToCentralCache(cl, drop);
+ }
+ list->clear_lowwatermark();
+ }
+
+ //int64 finish = CycleClock::Now();
+ //CycleTimer ct;
+ //MESSAGE("GC: %.0f ns\n", ct.CyclesToUsec(finish-start)*1000.0);
+}
+
+void TCMalloc_ThreadCache::PickNextSample(size_t k) {
+ // Make next "random" number
+ // x^32+x^22+x^2+x^1+1 is a primitive polynomial for random numbers
+ static const uint32_t kPoly = (1 << 22) | (1 << 2) | (1 << 1) | (1 << 0);
+ uint32_t r = rnd_;
+ rnd_ = (r << 1) ^ ((static_cast<int32_t>(r) >> 31) & kPoly);
+
+ // Next point is "rnd_ % (sample_period)". I.e., average
+ // increment is "sample_period/2".
+ const int flag_value = static_cast<int>(FLAGS_tcmalloc_sample_parameter);
+ static int last_flag_value = -1;
+
+ if (flag_value != last_flag_value) {
+ SpinLockHolder h(&sample_period_lock);
+ int i;
+ for (i = 0; i < (static_cast<int>(sizeof(primes_list)/sizeof(primes_list[0])) - 1); i++) {
+ if (primes_list[i] >= flag_value) {
+ break;
+ }
+ }
+ sample_period = primes_list[i];
+ last_flag_value = flag_value;
+ }
+
+ bytes_until_sample_ += rnd_ % sample_period;
+
+ if (k > (static_cast<size_t>(-1) >> 2)) {
+ // If the user has asked for a huge allocation then it is possible
+ // for the code below to loop infinitely. Just return (note that
+ // this throws off the sampling accuracy somewhat, but a user who
+ // is allocating more than 1G of memory at a time can live with a
+ // minor inaccuracy in profiling of small allocations, and also
+ // would rather not wait for the loop below to terminate).
+ return;
+ }
+
+ while (bytes_until_sample_ < k) {
+ // Increase bytes_until_sample_ by enough average sampling periods
+ // (sample_period >> 1) to allow us to sample past the current
+ // allocation.
+ bytes_until_sample_ += (sample_period >> 1);
+ }
+
+ bytes_until_sample_ -= k;
+}
+
+void TCMalloc_ThreadCache::InitModule() {
+ // There is a slight potential race here because of double-checked
+ // locking idiom. However, as long as the program does a small
+ // allocation before switching to multi-threaded mode, we will be
+ // fine. We increase the chances of doing such a small allocation
+ // by doing one in the constructor of the module_enter_exit_hook
+ // object declared below.
+ SpinLockHolder h(&pageheap_lock);
+ if (!phinited) {
+#ifdef WTF_CHANGES
+ InitTSD();
+#endif
+ InitSizeClasses();
+ threadheap_allocator.Init();
+ span_allocator.Init();
+ span_allocator.New(); // Reduce cache conflicts
+ span_allocator.New(); // Reduce cache conflicts
+ stacktrace_allocator.Init();
+ DLL_Init(&sampled_objects);
+ for (size_t i = 0; i < kNumClasses; ++i) {
+ central_cache[i].Init(i);
+ }
+ pageheap->init();
+ phinited = 1;
+#if defined(WTF_CHANGES) && OS(DARWIN)
+ FastMallocZone::init();
+#endif
+ }
+}
+
+inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::NewHeap(ThreadIdentifier tid) {
+ // Create the heap and add it to the linked list
+ TCMalloc_ThreadCache *heap = threadheap_allocator.New();
+ heap->Init(tid);
+ heap->next_ = thread_heaps;
+ heap->prev_ = NULL;
+ if (thread_heaps != NULL) thread_heaps->prev_ = heap;
+ thread_heaps = heap;
+ thread_heap_count++;
+ RecomputeThreadCacheSize();
+ return heap;
+}
+
+inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetThreadHeap() {
+#ifdef HAVE_TLS
+ // __thread is faster, but only when the kernel supports it
+ if (KernelSupportsTLS())
+ return threadlocal_heap;
+#elif OS(WINDOWS)
+ return static_cast<TCMalloc_ThreadCache*>(TlsGetValue(tlsIndex));
+#else
+ return static_cast<TCMalloc_ThreadCache*>(pthread_getspecific(heap_key));
+#endif
+}
+
+inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetCache() {
+ TCMalloc_ThreadCache* ptr = NULL;
+ if (!tsd_inited) {
+ InitModule();
+ } else {
+ ptr = GetThreadHeap();
+ }
+ if (ptr == NULL) ptr = CreateCacheIfNecessary();
+ return ptr;
+}
+
+// In deletion paths, we do not try to create a thread-cache. This is
+// because we may be in the thread destruction code and may have
+// already cleaned up the cache for this thread.
+inline TCMalloc_ThreadCache* TCMalloc_ThreadCache::GetCacheIfPresent() {
+ if (!tsd_inited) return NULL;
+ void* const p = GetThreadHeap();
+ return reinterpret_cast<TCMalloc_ThreadCache*>(p);
+}
+
+void TCMalloc_ThreadCache::InitTSD() {
+ ASSERT(!tsd_inited);
+#if USE(PTHREAD_GETSPECIFIC_DIRECT)
+ pthread_key_init_np(heap_key, DestroyThreadCache);
+#else
+ pthread_key_create(&heap_key, DestroyThreadCache);
+#endif
+#if OS(WINDOWS)
+ tlsIndex = TlsAlloc();
+#endif
+ tsd_inited = true;
+
+#if !OS(WINDOWS)
+ // We may have used a fake pthread_t for the main thread. Fix it.
+ pthread_t zero;
+ memset(&zero, 0, sizeof(zero));
+#endif
+#ifndef WTF_CHANGES
+ SpinLockHolder h(&pageheap_lock);
+#else
+ ASSERT(pageheap_lock.IsHeld());
+#endif
+ for (TCMalloc_ThreadCache* h = thread_heaps; h != NULL; h = h->next_) {
+#if OS(WINDOWS)
+ if (h->tid_ == 0) {
+ h->tid_ = GetCurrentThreadId();
+ }
+#else
+ if (pthread_equal(h->tid_, zero)) {
+ h->tid_ = pthread_self();
+ }
+#endif
+ }
+}
+
+TCMalloc_ThreadCache* TCMalloc_ThreadCache::CreateCacheIfNecessary() {
+ // Initialize per-thread data if necessary
+ TCMalloc_ThreadCache* heap = NULL;
+ {
+ SpinLockHolder h(&pageheap_lock);
+
+#if OS(WINDOWS)
+ DWORD me;
+ if (!tsd_inited) {
+ me = 0;
+ } else {
+ me = GetCurrentThreadId();
+ }
+#else
+ // Early on in glibc's life, we cannot even call pthread_self()
+ pthread_t me;
+ if (!tsd_inited) {
+ memset(&me, 0, sizeof(me));
+ } else {
+ me = pthread_self();
+ }
+#endif
+
+ // This may be a recursive malloc call from pthread_setspecific()
+ // In that case, the heap for this thread has already been created
+ // and added to the linked list. So we search for that first.
+ for (TCMalloc_ThreadCache* h = thread_heaps; h != NULL; h = h->next_) {
+#if OS(WINDOWS)
+ if (h->tid_ == me) {
+#else
+ if (pthread_equal(h->tid_, me)) {
+#endif
+ heap = h;
+ break;
+ }
+ }
+
+ if (heap == NULL) heap = NewHeap(me);
+ }
+
+ // We call pthread_setspecific() outside the lock because it may
+ // call malloc() recursively. The recursive call will never get
+ // here again because it will find the already allocated heap in the
+ // linked list of heaps.
+ if (!heap->in_setspecific_ && tsd_inited) {
+ heap->in_setspecific_ = true;
+ setThreadHeap(heap);
+ }
+ return heap;
+}
+
+void TCMalloc_ThreadCache::BecomeIdle() {
+ if (!tsd_inited) return; // No caches yet
+ TCMalloc_ThreadCache* heap = GetThreadHeap();
+ if (heap == NULL) return; // No thread cache to remove
+ if (heap->in_setspecific_) return; // Do not disturb the active caller
+
+ heap->in_setspecific_ = true;
+ setThreadHeap(NULL);
+#ifdef HAVE_TLS
+ // Also update the copy in __thread
+ threadlocal_heap = NULL;
+#endif
+ heap->in_setspecific_ = false;
+ if (GetThreadHeap() == heap) {
+ // Somehow heap got reinstated by a recursive call to malloc
+ // from pthread_setspecific. We give up in this case.
+ return;
+ }
+
+ // We can now get rid of the heap
+ DeleteCache(heap);
+}
+
+void TCMalloc_ThreadCache::DestroyThreadCache(void* ptr) {
+ // Note that "ptr" cannot be NULL since pthread promises not
+ // to invoke the destructor on NULL values, but for safety,
+ // we check anyway.
+ if (ptr == NULL) return;
+#ifdef HAVE_TLS
+ // Prevent fast path of GetThreadHeap() from returning heap.
+ threadlocal_heap = NULL;
+#endif
+ DeleteCache(reinterpret_cast<TCMalloc_ThreadCache*>(ptr));
+}
+
+void TCMalloc_ThreadCache::DeleteCache(TCMalloc_ThreadCache* heap) {
+ // Remove all memory from heap
+ heap->Cleanup();
+
+ // Remove from linked list
+ SpinLockHolder h(&pageheap_lock);
+ if (heap->next_ != NULL) heap->next_->prev_ = heap->prev_;
+ if (heap->prev_ != NULL) heap->prev_->next_ = heap->next_;
+ if (thread_heaps == heap) thread_heaps = heap->next_;
+ thread_heap_count--;
+ RecomputeThreadCacheSize();
+
+ threadheap_allocator.Delete(heap);
+}
+
+void TCMalloc_ThreadCache::RecomputeThreadCacheSize() {
+ // Divide available space across threads
+ int n = thread_heap_count > 0 ? thread_heap_count : 1;
+ size_t space = overall_thread_cache_size / n;
+
+ // Limit to allowed range
+ if (space < kMinThreadCacheSize) space = kMinThreadCacheSize;
+ if (space > kMaxThreadCacheSize) space = kMaxThreadCacheSize;
+
+ per_thread_cache_size = space;
+}
+
+void TCMalloc_ThreadCache::Print() const {
+ for (size_t cl = 0; cl < kNumClasses; ++cl) {
+ MESSAGE(" %5" PRIuS " : %4d len; %4d lo\n",
+ ByteSizeForClass(cl),
+ list_[cl].length(),
+ list_[cl].lowwatermark());
+ }
+}
+
+// Extract interesting stats
+struct TCMallocStats {
+ uint64_t system_bytes; // Bytes alloced from system
+ uint64_t thread_bytes; // Bytes in thread caches
+ uint64_t central_bytes; // Bytes in central cache
+ uint64_t transfer_bytes; // Bytes in central transfer cache
+ uint64_t pageheap_bytes; // Bytes in page heap
+ uint64_t metadata_bytes; // Bytes alloced for metadata
+};
+
+#ifndef WTF_CHANGES
+// Get stats into "r". Also get per-size-class counts if class_count != NULL
+static void ExtractStats(TCMallocStats* r, uint64_t* class_count) {
+ r->central_bytes = 0;
+ r->transfer_bytes = 0;
+ for (int cl = 0; cl < kNumClasses; ++cl) {
+ const int length = central_cache[cl].length();
+ const int tc_length = central_cache[cl].tc_length();
+ r->central_bytes += static_cast<uint64_t>(ByteSizeForClass(cl)) * length;
+ r->transfer_bytes +=
+ static_cast<uint64_t>(ByteSizeForClass(cl)) * tc_length;
+ if (class_count) class_count[cl] = length + tc_length;
+ }
+
+ // Add stats from per-thread heaps
+ r->thread_bytes = 0;
+ { // scope
+ SpinLockHolder h(&pageheap_lock);
+ for (TCMalloc_ThreadCache* h = thread_heaps; h != NULL; h = h->next_) {
+ r->thread_bytes += h->Size();
+ if (class_count) {
+ for (size_t cl = 0; cl < kNumClasses; ++cl) {
+ class_count[cl] += h->freelist_length(cl);
+ }
+ }
+ }
+ }
+
+ { //scope
+ SpinLockHolder h(&pageheap_lock);
+ r->system_bytes = pageheap->SystemBytes();
+ r->metadata_bytes = metadata_system_bytes;
+ r->pageheap_bytes = pageheap->FreeBytes();
+ }
+}
+#endif
+
+#ifndef WTF_CHANGES
+// WRITE stats to "out"
+static void DumpStats(TCMalloc_Printer* out, int level) {
+ TCMallocStats stats;
+ uint64_t class_count[kNumClasses];
+ ExtractStats(&stats, (level >= 2 ? class_count : NULL));
+
+ if (level >= 2) {
+ out->printf("------------------------------------------------\n");
+ uint64_t cumulative = 0;
+ for (int cl = 0; cl < kNumClasses; ++cl) {
+ if (class_count[cl] > 0) {
+ uint64_t class_bytes = class_count[cl] * ByteSizeForClass(cl);
+ cumulative += class_bytes;
+ out->printf("class %3d [ %8" PRIuS " bytes ] : "
+ "%8" PRIu64 " objs; %5.1f MB; %5.1f cum MB\n",
+ cl, ByteSizeForClass(cl),
+ class_count[cl],
+ class_bytes / 1048576.0,
+ cumulative / 1048576.0);
+ }
+ }
+
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->Dump(out);
+ }
+
+ const uint64_t bytes_in_use = stats.system_bytes
+ - stats.pageheap_bytes
+ - stats.central_bytes
+ - stats.transfer_bytes
+ - stats.thread_bytes;
+
+ out->printf("------------------------------------------------\n"
+ "MALLOC: %12" PRIu64 " Heap size\n"
+ "MALLOC: %12" PRIu64 " Bytes in use by application\n"
+ "MALLOC: %12" PRIu64 " Bytes free in page heap\n"
+ "MALLOC: %12" PRIu64 " Bytes free in central cache\n"
+ "MALLOC: %12" PRIu64 " Bytes free in transfer cache\n"
+ "MALLOC: %12" PRIu64 " Bytes free in thread caches\n"
+ "MALLOC: %12" PRIu64 " Spans in use\n"
+ "MALLOC: %12" PRIu64 " Thread heaps in use\n"
+ "MALLOC: %12" PRIu64 " Metadata allocated\n"
+ "------------------------------------------------\n",
+ stats.system_bytes,
+ bytes_in_use,
+ stats.pageheap_bytes,
+ stats.central_bytes,
+ stats.transfer_bytes,
+ stats.thread_bytes,
+ uint64_t(span_allocator.inuse()),
+ uint64_t(threadheap_allocator.inuse()),
+ stats.metadata_bytes);
+}
+
+static void PrintStats(int level) {
+ const int kBufferSize = 16 << 10;
+ char* buffer = new char[kBufferSize];
+ TCMalloc_Printer printer(buffer, kBufferSize);
+ DumpStats(&printer, level);
+ write(STDERR_FILENO, buffer, strlen(buffer));
+ delete[] buffer;
+}
+
+static void** DumpStackTraces() {
+ // Count how much space we need
+ int needed_slots = 0;
+ {
+ SpinLockHolder h(&pageheap_lock);
+ for (Span* s = sampled_objects.next; s != &sampled_objects; s = s->next) {
+ StackTrace* stack = reinterpret_cast<StackTrace*>(s->objects);
+ needed_slots += 3 + stack->depth;
+ }
+ needed_slots += 100; // Slop in case sample grows
+ needed_slots += needed_slots/8; // An extra 12.5% slop
+ }
+
+ void** result = new void*[needed_slots];
+ if (result == NULL) {
+ MESSAGE("tcmalloc: could not allocate %d slots for stack traces\n",
+ needed_slots);
+ return NULL;
+ }
+
+ SpinLockHolder h(&pageheap_lock);
+ int used_slots = 0;
+ for (Span* s = sampled_objects.next; s != &sampled_objects; s = s->next) {
+ ASSERT(used_slots < needed_slots); // Need to leave room for terminator
+ StackTrace* stack = reinterpret_cast<StackTrace*>(s->objects);
+ if (used_slots + 3 + stack->depth >= needed_slots) {
+ // No more room
+ break;
+ }
+
+ result[used_slots+0] = reinterpret_cast<void*>(static_cast<uintptr_t>(1));
+ result[used_slots+1] = reinterpret_cast<void*>(stack->size);
+ result[used_slots+2] = reinterpret_cast<void*>(stack->depth);
+ for (int d = 0; d < stack->depth; d++) {
+ result[used_slots+3+d] = stack->stack[d];
+ }
+ used_slots += 3 + stack->depth;
+ }
+ result[used_slots] = reinterpret_cast<void*>(static_cast<uintptr_t>(0));
+ return result;
+}
+#endif
+
+#ifndef WTF_CHANGES
+
+// TCMalloc's support for extra malloc interfaces
+class TCMallocImplementation : public MallocExtension {
+ public:
+ virtual void GetStats(char* buffer, int buffer_length) {
+ ASSERT(buffer_length > 0);
+ TCMalloc_Printer printer(buffer, buffer_length);
+
+ // Print level one stats unless lots of space is available
+ if (buffer_length < 10000) {
+ DumpStats(&printer, 1);
+ } else {
+ DumpStats(&printer, 2);
+ }
+ }
+
+ virtual void** ReadStackTraces() {
+ return DumpStackTraces();
+ }
+
+ virtual bool GetNumericProperty(const char* name, size_t* value) {
+ ASSERT(name != NULL);
+
+ if (strcmp(name, "generic.current_allocated_bytes") == 0) {
+ TCMallocStats stats;
+ ExtractStats(&stats, NULL);
+ *value = stats.system_bytes
+ - stats.thread_bytes
+ - stats.central_bytes
+ - stats.pageheap_bytes;
+ return true;
+ }
+
+ if (strcmp(name, "generic.heap_size") == 0) {
+ TCMallocStats stats;
+ ExtractStats(&stats, NULL);
+ *value = stats.system_bytes;
+ return true;
+ }
+
+ if (strcmp(name, "tcmalloc.slack_bytes") == 0) {
+ // We assume that bytes in the page heap are not fragmented too
+ // badly, and are therefore available for allocation.
+ SpinLockHolder l(&pageheap_lock);
+ *value = pageheap->FreeBytes();
+ return true;
+ }
+
+ if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) {
+ SpinLockHolder l(&pageheap_lock);
+ *value = overall_thread_cache_size;
+ return true;
+ }
+
+ if (strcmp(name, "tcmalloc.current_total_thread_cache_bytes") == 0) {
+ TCMallocStats stats;
+ ExtractStats(&stats, NULL);
+ *value = stats.thread_bytes;
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual bool SetNumericProperty(const char* name, size_t value) {
+ ASSERT(name != NULL);
+
+ if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) {
+ // Clip the value to a reasonable range
+ if (value < kMinThreadCacheSize) value = kMinThreadCacheSize;
+ if (value > (1<<30)) value = (1<<30); // Limit to 1GB
+
+ SpinLockHolder l(&pageheap_lock);
+ overall_thread_cache_size = static_cast<size_t>(value);
+ TCMalloc_ThreadCache::RecomputeThreadCacheSize();
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void MarkThreadIdle() {
+ TCMalloc_ThreadCache::BecomeIdle();
+ }
+
+ virtual void ReleaseFreeMemory() {
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->ReleaseFreePages();
+ }
+};
+#endif
+
+// The constructor allocates an object to ensure that initialization
+// runs before main(), and therefore we do not have a chance to become
+// multi-threaded before initialization. We also create the TSD key
+// here. Presumably by the time this constructor runs, glibc is in
+// good enough shape to handle pthread_key_create().
+//
+// The constructor also takes the opportunity to tell STL to use
+// tcmalloc. We want to do this early, before construct time, so
+// all user STL allocations go through tcmalloc (which works really
+// well for STL).
+//
+// The destructor prints stats when the program exits.
+class TCMallocGuard {
+ public:
+
+ TCMallocGuard() {
+#ifdef HAVE_TLS // this is true if the cc/ld/libc combo support TLS
+ // Check whether the kernel also supports TLS (needs to happen at runtime)
+ CheckIfKernelSupportsTLS();
+#endif
+#ifndef WTF_CHANGES
+#ifdef WIN32 // patch the windows VirtualAlloc, etc.
+ PatchWindowsFunctions(); // defined in windows/patch_functions.cc
+#endif
+#endif
+ free(malloc(1));
+ TCMalloc_ThreadCache::InitTSD();
+ free(malloc(1));
+#ifndef WTF_CHANGES
+ MallocExtension::Register(new TCMallocImplementation);
+#endif
+ }
+
+#ifndef WTF_CHANGES
+ ~TCMallocGuard() {
+ const char* env = getenv("MALLOCSTATS");
+ if (env != NULL) {
+ int level = atoi(env);
+ if (level < 1) level = 1;
+ PrintStats(level);
+ }
+#ifdef WIN32
+ UnpatchWindowsFunctions();
+#endif
+ }
+#endif
+};
+
+#ifndef WTF_CHANGES
+static TCMallocGuard module_enter_exit_hook;
+#endif
+
+
+//-------------------------------------------------------------------
+// Helpers for the exported routines below
+//-------------------------------------------------------------------
+
+#ifndef WTF_CHANGES
+
+static Span* DoSampledAllocation(size_t size) {
+
+ // Grab the stack trace outside the heap lock
+ StackTrace tmp;
+ tmp.depth = GetStackTrace(tmp.stack, kMaxStackDepth, 1);
+ tmp.size = size;
+
+ SpinLockHolder h(&pageheap_lock);
+ // Allocate span
+ Span *span = pageheap->New(pages(size == 0 ? 1 : size));
+ if (span == NULL) {
+ return NULL;
+ }
+
+ // Allocate stack trace
+ StackTrace *stack = stacktrace_allocator.New();
+ if (stack == NULL) {
+ // Sampling failed because of lack of memory
+ return span;
+ }
+
+ *stack = tmp;
+ span->sample = 1;
+ span->objects = stack;
+ DLL_Prepend(&sampled_objects, span);
+
+ return span;
+}
+#endif
+
+static inline bool CheckCachedSizeClass(void *ptr) {
+ PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ size_t cached_value = pageheap->GetSizeClassIfCached(p);
+ return cached_value == 0 ||
+ cached_value == pageheap->GetDescriptor(p)->sizeclass;
+}
+
+static inline void* CheckedMallocResult(void *result)
+{
+ ASSERT(result == 0 || CheckCachedSizeClass(result));
+ return result;
+}
+
+static inline void* SpanToMallocResult(Span *span) {
+ ASSERT_SPAN_COMMITTED(span);
+ pageheap->CacheSizeClass(span->start, 0);
+ return
+ CheckedMallocResult(reinterpret_cast<void*>(span->start << kPageShift));
+}
+
+#ifdef WTF_CHANGES
+template <bool crashOnFailure>
+#endif
+static ALWAYS_INLINE void* do_malloc(size_t size) {
+ void* ret = NULL;
+
+#ifdef WTF_CHANGES
+ ASSERT(!isForbidden());
+#endif
+
+ // The following call forces module initialization
+ TCMalloc_ThreadCache* heap = TCMalloc_ThreadCache::GetCache();
+#ifndef WTF_CHANGES
+ if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) {
+ Span* span = DoSampledAllocation(size);
+ if (span != NULL) {
+ ret = SpanToMallocResult(span);
+ }
+ } else
+#endif
+ if (size > kMaxSize) {
+ // Use page-level allocator
+ SpinLockHolder h(&pageheap_lock);
+ Span* span = pageheap->New(pages(size));
+ if (span != NULL) {
+ ret = SpanToMallocResult(span);
+ }
+ } else {
+ // The common case, and also the simplest. This just pops the
+ // size-appropriate freelist, afer replenishing it if it's empty.
+ ret = CheckedMallocResult(heap->Allocate(size));
+ }
+ if (!ret) {
+#ifdef WTF_CHANGES
+ if (crashOnFailure) // This branch should be optimized out by the compiler.
+ CRASH();
+#else
+ errno = ENOMEM;
+#endif
+ }
+ return ret;
+}
+
+static ALWAYS_INLINE void do_free(void* ptr) {
+ if (ptr == NULL) return;
+ ASSERT(pageheap != NULL); // Should not call free() before malloc()
+ const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ Span* span = NULL;
+ size_t cl = pageheap->GetSizeClassIfCached(p);
+
+ if (cl == 0) {
+ span = pageheap->GetDescriptor(p);
+ cl = span->sizeclass;
+ pageheap->CacheSizeClass(p, cl);
+ }
+ if (cl != 0) {
+#ifndef NO_TCMALLOC_SAMPLES
+ ASSERT(!pageheap->GetDescriptor(p)->sample);
+#endif
+ TCMalloc_ThreadCache* heap = TCMalloc_ThreadCache::GetCacheIfPresent();
+ if (heap != NULL) {
+ heap->Deallocate(ptr, cl);
+ } else {
+ // Delete directly into central cache
+ SLL_SetNext(ptr, NULL);
+ central_cache[cl].InsertRange(ptr, ptr, 1);
+ }
+ } else {
+ SpinLockHolder h(&pageheap_lock);
+ ASSERT(reinterpret_cast<uintptr_t>(ptr) % kPageSize == 0);
+ ASSERT(span != NULL && span->start == p);
+#ifndef NO_TCMALLOC_SAMPLES
+ if (span->sample) {
+ DLL_Remove(span);
+ stacktrace_allocator.Delete(reinterpret_cast<StackTrace*>(span->objects));
+ span->objects = NULL;
+ }
+#endif
+ pageheap->Delete(span);
+ }
+}
+
+#ifndef WTF_CHANGES
+// For use by exported routines below that want specific alignments
+//
+// Note: this code can be slow, and can significantly fragment memory.
+// The expectation is that memalign/posix_memalign/valloc/pvalloc will
+// not be invoked very often. This requirement simplifies our
+// implementation and allows us to tune for expected allocation
+// patterns.
+static void* do_memalign(size_t align, size_t size) {
+ ASSERT((align & (align - 1)) == 0);
+ ASSERT(align > 0);
+ if (pageheap == NULL) TCMalloc_ThreadCache::InitModule();
+
+ // Allocate at least one byte to avoid boundary conditions below
+ if (size == 0) size = 1;
+
+ if (size <= kMaxSize && align < kPageSize) {
+ // Search through acceptable size classes looking for one with
+ // enough alignment. This depends on the fact that
+ // InitSizeClasses() currently produces several size classes that
+ // are aligned at powers of two. We will waste time and space if
+ // we miss in the size class array, but that is deemed acceptable
+ // since memalign() should be used rarely.
+ size_t cl = SizeClass(size);
+ while (cl < kNumClasses && ((class_to_size[cl] & (align - 1)) != 0)) {
+ cl++;
+ }
+ if (cl < kNumClasses) {
+ TCMalloc_ThreadCache* heap = TCMalloc_ThreadCache::GetCache();
+ return CheckedMallocResult(heap->Allocate(class_to_size[cl]));
+ }
+ }
+
+ // We will allocate directly from the page heap
+ SpinLockHolder h(&pageheap_lock);
+
+ if (align <= kPageSize) {
+ // Any page-level allocation will be fine
+ // TODO: We could put the rest of this page in the appropriate
+ // TODO: cache but it does not seem worth it.
+ Span* span = pageheap->New(pages(size));
+ return span == NULL ? NULL : SpanToMallocResult(span);
+ }
+
+ // Allocate extra pages and carve off an aligned portion
+ const Length alloc = pages(size + align);
+ Span* span = pageheap->New(alloc);
+ if (span == NULL) return NULL;
+
+ // Skip starting portion so that we end up aligned
+ Length skip = 0;
+ while ((((span->start+skip) << kPageShift) & (align - 1)) != 0) {
+ skip++;
+ }
+ ASSERT(skip < alloc);
+ if (skip > 0) {
+ Span* rest = pageheap->Split(span, skip);
+ pageheap->Delete(span);
+ span = rest;
+ }
+
+ // Skip trailing portion that we do not need to return
+ const Length needed = pages(size);
+ ASSERT(span->length >= needed);
+ if (span->length > needed) {
+ Span* trailer = pageheap->Split(span, needed);
+ pageheap->Delete(trailer);
+ }
+ return SpanToMallocResult(span);
+}
+#endif
+
+// Helpers for use by exported routines below:
+
+#ifndef WTF_CHANGES
+static inline void do_malloc_stats() {
+ PrintStats(1);
+}
+#endif
+
+static inline int do_mallopt(int, int) {
+ return 1; // Indicates error
+}
+
+#ifdef HAVE_STRUCT_MALLINFO // mallinfo isn't defined on freebsd, for instance
+static inline struct mallinfo do_mallinfo() {
+ TCMallocStats stats;
+ ExtractStats(&stats, NULL);
+
+ // Just some of the fields are filled in.
+ struct mallinfo info;
+ memset(&info, 0, sizeof(info));
+
+ // Unfortunately, the struct contains "int" field, so some of the
+ // size values will be truncated.
+ info.arena = static_cast<int>(stats.system_bytes);
+ info.fsmblks = static_cast<int>(stats.thread_bytes
+ + stats.central_bytes
+ + stats.transfer_bytes);
+ info.fordblks = static_cast<int>(stats.pageheap_bytes);
+ info.uordblks = static_cast<int>(stats.system_bytes
+ - stats.thread_bytes
+ - stats.central_bytes
+ - stats.transfer_bytes
+ - stats.pageheap_bytes);
+
+ return info;
+}
+#endif
+
+//-------------------------------------------------------------------
+// Exported routines
+//-------------------------------------------------------------------
+
+// CAVEAT: The code structure below ensures that MallocHook methods are always
+// called from the stack frame of the invoked allocation function.
+// heap-checker.cc depends on this to start a stack trace from
+// the call to the (de)allocation function.
+
+#ifndef WTF_CHANGES
+extern "C"
+#else
+#define do_malloc do_malloc<crashOnFailure>
+
+template <bool crashOnFailure>
+ALWAYS_INLINE void* malloc(size_t);
+
+void* fastMalloc(size_t size)
+{
+ return malloc<true>(size);
+}
+
+TryMallocReturnValue tryFastMalloc(size_t size)
+{
+ return malloc<false>(size);
+}
+
+template <bool crashOnFailure>
+ALWAYS_INLINE
+#endif
+void* malloc(size_t size) {
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= size) // If overflow would occur...
+ return 0;
+ void* result = do_malloc(size + Internal::ValidationBufferSize);
+ if (!result)
+ return 0;
+
+ Internal::ValidationHeader* header = static_cast<Internal::ValidationHeader*>(result);
+ header->m_size = size;
+ header->m_type = Internal::AllocTypeMalloc;
+ header->m_prefix = static_cast<unsigned>(Internal::ValidationPrefix);
+ result = header + 1;
+ *Internal::fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
+#else
+ void* result = do_malloc(size);
+#endif
+
+#ifndef WTF_CHANGES
+ MallocHook::InvokeNewHook(result, size);
+#endif
+ return result;
+}
+
+#ifndef WTF_CHANGES
+extern "C"
+#endif
+void free(void* ptr) {
+#ifndef WTF_CHANGES
+ MallocHook::InvokeDeleteHook(ptr);
+#endif
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (!ptr)
+ return;
+
+ fastMallocValidate(ptr);
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(ptr);
+ memset(ptr, 0xCC, header->m_size);
+ do_free(header);
+#else
+ do_free(ptr);
+#endif
+}
+
+#ifndef WTF_CHANGES
+extern "C"
+#else
+template <bool crashOnFailure>
+ALWAYS_INLINE void* calloc(size_t, size_t);
+
+void* fastCalloc(size_t n, size_t elem_size)
+{
+ void* result = calloc<true>(n, elem_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
+}
+
+TryMallocReturnValue tryFastCalloc(size_t n, size_t elem_size)
+{
+ void* result = calloc<false>(n, elem_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
+}
+
+template <bool crashOnFailure>
+ALWAYS_INLINE
+#endif
+void* calloc(size_t n, size_t elem_size) {
+ size_t totalBytes = n * elem_size;
+
+ // Protect against overflow
+ if (n > 1 && elem_size && (totalBytes / elem_size) != n)
+ return 0;
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ void* result = malloc<crashOnFailure>(totalBytes);
+ if (!result)
+ return 0;
+
+ memset(result, 0, totalBytes);
+ fastMallocValidate(result);
+#else
+ void* result = do_malloc(totalBytes);
+ if (result != NULL) {
+ memset(result, 0, totalBytes);
+ }
+#endif
+
+#ifndef WTF_CHANGES
+ MallocHook::InvokeNewHook(result, totalBytes);
+#endif
+ return result;
+}
+
+// Since cfree isn't used anywhere, we don't compile it in.
+#ifndef WTF_CHANGES
+#ifndef WTF_CHANGES
+extern "C"
+#endif
+void cfree(void* ptr) {
+#ifndef WTF_CHANGES
+ MallocHook::InvokeDeleteHook(ptr);
+#endif
+ do_free(ptr);
+}
+#endif
+
+#ifndef WTF_CHANGES
+extern "C"
+#else
+template <bool crashOnFailure>
+ALWAYS_INLINE void* realloc(void*, size_t);
+
+void* fastRealloc(void* old_ptr, size_t new_size)
+{
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(old_ptr);
+#endif
+ void* result = realloc<true>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
+}
+
+TryMallocReturnValue tryFastRealloc(void* old_ptr, size_t new_size)
+{
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(old_ptr);
+#endif
+ void* result = realloc<false>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
+}
+
+template <bool crashOnFailure>
+ALWAYS_INLINE
+#endif
+void* realloc(void* old_ptr, size_t new_size) {
+ if (old_ptr == NULL) {
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ void* result = malloc<crashOnFailure>(new_size);
+#else
+ void* result = do_malloc(new_size);
+#ifndef WTF_CHANGES
+ MallocHook::InvokeNewHook(result, new_size);
+#endif
+#endif
+ return result;
+ }
+ if (new_size == 0) {
+#ifndef WTF_CHANGES
+ MallocHook::InvokeDeleteHook(old_ptr);
+#endif
+ free(old_ptr);
+ return NULL;
+ }
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= new_size) // If overflow would occur...
+ return 0;
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(old_ptr);
+ fastMallocValidate(old_ptr);
+ old_ptr = header;
+ header->m_size = new_size;
+ new_size += Internal::ValidationBufferSize;
+#endif
+
+ // Get the size of the old entry
+ const PageID p = reinterpret_cast<uintptr_t>(old_ptr) >> kPageShift;
+ size_t cl = pageheap->GetSizeClassIfCached(p);
+ Span *span = NULL;
+ size_t old_size;
+ if (cl == 0) {
+ span = pageheap->GetDescriptor(p);
+ cl = span->sizeclass;
+ pageheap->CacheSizeClass(p, cl);
+ }
+ if (cl != 0) {
+ old_size = ByteSizeForClass(cl);
+ } else {
+ ASSERT(span != NULL);
+ old_size = span->length << kPageShift;
+ }
+
+ // Reallocate if the new size is larger than the old size,
+ // or if the new size is significantly smaller than the old size.
+ if ((new_size > old_size) || (AllocationSize(new_size) < old_size)) {
+ // Need to reallocate
+ void* new_ptr = do_malloc(new_size);
+ if (new_ptr == NULL) {
+ return NULL;
+ }
+#ifndef WTF_CHANGES
+ MallocHook::InvokeNewHook(new_ptr, new_size);
+#endif
+ memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size));
+#ifndef WTF_CHANGES
+ MallocHook::InvokeDeleteHook(old_ptr);
+#endif
+ // We could use a variant of do_free() that leverages the fact
+ // that we already know the sizeclass of old_ptr. The benefit
+ // would be small, so don't bother.
+ do_free(old_ptr);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ new_ptr = static_cast<Internal::ValidationHeader*>(new_ptr) + 1;
+ *Internal::fastMallocValidationSuffix(new_ptr) = Internal::ValidationSuffix;
+#endif
+ return new_ptr;
+ } else {
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ old_ptr = static_cast<Internal::ValidationHeader*>(old_ptr) + 1; // Set old_ptr back to the user pointer.
+ *Internal::fastMallocValidationSuffix(old_ptr) = Internal::ValidationSuffix;
+#endif
+ return old_ptr;
+ }
+}
+
+#ifdef WTF_CHANGES
+#undef do_malloc
+#else
+
+static SpinLock set_new_handler_lock = SPINLOCK_INITIALIZER;
+
+static inline void* cpp_alloc(size_t size, bool nothrow) {
+ for (;;) {
+ void* p = do_malloc(size);
+#ifdef PREANSINEW
+ return p;
+#else
+ if (p == NULL) { // allocation failed
+ // Get the current new handler. NB: this function is not
+ // thread-safe. We make a feeble stab at making it so here, but
+ // this lock only protects against tcmalloc interfering with
+ // itself, not with other libraries calling set_new_handler.
+ std::new_handler nh;
+ {
+ SpinLockHolder h(&set_new_handler_lock);
+ nh = std::set_new_handler(0);
+ (void) std::set_new_handler(nh);
+ }
+ // If no new_handler is established, the allocation failed.
+ if (!nh) {
+ if (nothrow) return 0;
+ throw std::bad_alloc();
+ }
+ // Otherwise, try the new_handler. If it returns, retry the
+ // allocation. If it throws std::bad_alloc, fail the allocation.
+ // if it throws something else, don't interfere.
+ try {
+ (*nh)();
+ } catch (const std::bad_alloc&) {
+ if (!nothrow) throw;
+ return p;
+ }
+ } else { // allocation success
+ return p;
+ }
+#endif
+ }
+}
+
+#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
+ // it's in, and new just calls cpp_alloc, the optimizer may fold the
+ // new call into cpp_alloc, which messes up our whole section-based
+ // stacktracing (see ATTRIBUTE_SECTION, above). This ensures cpp_alloc
+ // isn't the last thing this fn calls, and prevents the folding.
+ MallocHook::InvokeNewHook(p, size);
+ return p;
+}
+
+void* operator new(size_t size, const std::nothrow_t&) __THROW {
+ void* p = cpp_alloc(size, true);
+ MallocHook::InvokeNewHook(p, size);
+ return p;
+}
+
+void operator delete(void* p) __THROW {
+ MallocHook::InvokeDeleteHook(p);
+ do_free(p);
+}
+
+void operator delete(void* p, const std::nothrow_t&) __THROW {
+ MallocHook::InvokeDeleteHook(p);
+ do_free(p);
+}
+
+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
+ // it's in, and new just calls cpp_alloc, the optimizer may fold the
+ // new call into cpp_alloc, which messes up our whole section-based
+ // stacktracing (see ATTRIBUTE_SECTION, above). This ensures cpp_alloc
+ // isn't the last thing this fn calls, and prevents the folding.
+ MallocHook::InvokeNewHook(p, size);
+ return p;
+}
+
+void* operator new[](size_t size, const std::nothrow_t&) __THROW {
+ void* p = cpp_alloc(size, true);
+ MallocHook::InvokeNewHook(p, size);
+ return p;
+}
+
+void operator delete[](void* p) __THROW {
+ MallocHook::InvokeDeleteHook(p);
+ do_free(p);
+}
+
+void operator delete[](void* p, const std::nothrow_t&) __THROW {
+ MallocHook::InvokeDeleteHook(p);
+ 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);
+ return result;
+}
+
+extern "C" int posix_memalign(void** result_ptr, size_t align, size_t size)
+ __THROW {
+ if (((align % sizeof(void*)) != 0) ||
+ ((align & (align - 1)) != 0) ||
+ (align == 0)) {
+ return EINVAL;
+ }
+
+ void* result = do_memalign(align, size);
+ MallocHook::InvokeNewHook(result, size);
+ if (result == NULL) {
+ return ENOMEM;
+ } else {
+ *result_ptr = result;
+ return 0;
+ }
+}
+
+static size_t pagesize = 0;
+
+extern "C" void* valloc(size_t size) __THROW {
+ // Allocate page-aligned object of length >= size bytes
+ if (pagesize == 0) pagesize = getpagesize();
+ void* result = do_memalign(pagesize, size);
+ MallocHook::InvokeNewHook(result, size);
+ return result;
+}
+
+extern "C" void* pvalloc(size_t size) __THROW {
+ // Round up size to a multiple of pagesize
+ if (pagesize == 0) pagesize = getpagesize();
+ size = (size + pagesize - 1) & ~(pagesize - 1);
+ void* result = do_memalign(pagesize, size);
+ MallocHook::InvokeNewHook(result, size);
+ return result;
+}
+
+extern "C" void malloc_stats(void) {
+ do_malloc_stats();
+}
+
+extern "C" int mallopt(int cmd, int value) {
+ return do_mallopt(cmd, value);
+}
+
+#ifdef HAVE_STRUCT_MALLINFO
+extern "C" struct mallinfo mallinfo(void) {
+ return do_mallinfo();
+}
+#endif
+
+//-------------------------------------------------------------------
+// Some library routines on RedHat 9 allocate memory using malloc()
+// and free it using __libc_free() (or vice-versa). Since we provide
+// our own implementations of malloc/free, we need to make sure that
+// the __libc_XXX variants (defined as part of glibc) also point to
+// the same implementations.
+//-------------------------------------------------------------------
+
+#if defined(__GLIBC__)
+extern "C" {
+#if COMPILER(GCC) && !defined(__MACH__) && defined(HAVE___ATTRIBUTE__)
+ // Potentially faster variants that use the gcc alias extension.
+ // Mach-O (Darwin) does not support weak aliases, hence the __MACH__ check.
+# define ALIAS(x) __attribute__ ((weak, alias (x)))
+ void* __libc_malloc(size_t size) ALIAS("malloc");
+ void __libc_free(void* ptr) ALIAS("free");
+ void* __libc_realloc(void* ptr, size_t size) ALIAS("realloc");
+ void* __libc_calloc(size_t n, size_t size) ALIAS("calloc");
+ void __libc_cfree(void* ptr) ALIAS("cfree");
+ void* __libc_memalign(size_t align, size_t s) ALIAS("memalign");
+ void* __libc_valloc(size_t size) ALIAS("valloc");
+ void* __libc_pvalloc(size_t size) ALIAS("pvalloc");
+ int __posix_memalign(void** r, size_t a, size_t s) ALIAS("posix_memalign");
+# undef ALIAS
+# else /* not __GNUC__ */
+ // Portable wrappers
+ void* __libc_malloc(size_t size) { return malloc(size); }
+ void __libc_free(void* ptr) { free(ptr); }
+ void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
+ void* __libc_calloc(size_t n, size_t size) { return calloc(n, size); }
+ void __libc_cfree(void* ptr) { cfree(ptr); }
+ void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); }
+ void* __libc_valloc(size_t size) { return valloc(size); }
+ void* __libc_pvalloc(size_t size) { return pvalloc(size); }
+ int __posix_memalign(void** r, size_t a, size_t s) {
+ return posix_memalign(r, a, s);
+ }
+# endif /* __GNUC__ */
+}
+#endif /* __GLIBC__ */
+
+// Override __libc_memalign in libc on linux boxes specially.
+// They have a bug in libc that causes them to (very rarely) allocate
+// with __libc_memalign() yet deallocate with free() and the
+// definitions above don't catch it.
+// This function is an exception to the rule of calling MallocHook method
+// from the stack frame of the allocation function;
+// heap-checker handles this special case explicitly.
+static void *MemalignOverride(size_t align, size_t size, const void *caller)
+ __THROW {
+ void* result = do_memalign(align, size);
+ MallocHook::InvokeNewHook(result, size);
+ return result;
+}
+void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride;
+
+#endif
+
+#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)
+{
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ return Internal::fastMallocValidationHeader(const_cast<void*>(ptr))->m_size;
+#else
+ 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;
+#endif
+}
+
+#if OS(DARWIN)
+
+class FreeObjectFinder {
+ const RemoteMemoryReader& m_reader;
+ HashSet<void*> m_freeObjects;
+
+public:
+ FreeObjectFinder(const RemoteMemoryReader& reader) : m_reader(reader) { }
+
+ void visit(void* ptr) { m_freeObjects.add(ptr); }
+ bool isFreeObject(void* ptr) const { return m_freeObjects.contains(ptr); }
+ bool isFreeObject(vm_address_t ptr) const { return isFreeObject(reinterpret_cast<void*>(ptr)); }
+ size_t freeObjectCount() const { return m_freeObjects.size(); }
+
+ void findFreeObjects(TCMalloc_ThreadCache* threadCache)
+ {
+ for (; threadCache; threadCache = (threadCache->next_ ? m_reader(threadCache->next_) : 0))
+ threadCache->enumerateFreeObjects(*this, m_reader);
+ }
+
+ void findFreeObjects(TCMalloc_Central_FreeListPadded* centralFreeList, size_t numSizes, TCMalloc_Central_FreeListPadded* remoteCentralFreeList)
+ {
+ for (unsigned i = 0; i < numSizes; i++)
+ centralFreeList[i].enumerateFreeObjects(*this, m_reader, remoteCentralFreeList + i);
+ }
+};
+
+class PageMapFreeObjectFinder {
+ const RemoteMemoryReader& m_reader;
+ FreeObjectFinder& m_freeObjectFinder;
+
+public:
+ PageMapFreeObjectFinder(const RemoteMemoryReader& reader, FreeObjectFinder& freeObjectFinder)
+ : m_reader(reader)
+ , m_freeObjectFinder(freeObjectFinder)
+ { }
+
+ int visit(void* ptr) const
+ {
+ if (!ptr)
+ return 1;
+
+ Span* span = m_reader(reinterpret_cast<Span*>(ptr));
+ if (!span)
+ return 1;
+
+ if (span->free) {
+ void* ptr = reinterpret_cast<void*>(span->start << kPageShift);
+ m_freeObjectFinder.visit(ptr);
+ } else if (span->sizeclass) {
+ // Walk the free list of the small-object span, keeping track of each object seen
+ for (void* nextObject = span->objects; nextObject; nextObject = m_reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
+ m_freeObjectFinder.visit(nextObject);
+ }
+ return span->length;
+ }
+};
+
+class PageMapMemoryUsageRecorder {
+ task_t m_task;
+ void* m_context;
+ unsigned m_typeMask;
+ vm_range_recorder_t* m_recorder;
+ const RemoteMemoryReader& m_reader;
+ const FreeObjectFinder& m_freeObjectFinder;
+
+ HashSet<void*> m_seenPointers;
+ Vector<Span*> m_coalescedSpans;
+
+public:
+ PageMapMemoryUsageRecorder(task_t task, void* context, unsigned typeMask, vm_range_recorder_t* recorder, const RemoteMemoryReader& reader, const FreeObjectFinder& freeObjectFinder)
+ : m_task(task)
+ , m_context(context)
+ , m_typeMask(typeMask)
+ , m_recorder(recorder)
+ , m_reader(reader)
+ , m_freeObjectFinder(freeObjectFinder)
+ { }
+
+ ~PageMapMemoryUsageRecorder()
+ {
+ ASSERT(!m_coalescedSpans.size());
+ }
+
+ void recordPendingRegions()
+ {
+ Span* lastSpan = m_coalescedSpans[m_coalescedSpans.size() - 1];
+ vm_range_t ptrRange = { m_coalescedSpans[0]->start << kPageShift, 0 };
+ ptrRange.size = (lastSpan->start << kPageShift) - ptrRange.address + (lastSpan->length * kPageSize);
+
+ // Mark the memory region the spans represent as a candidate for containing pointers
+ if (m_typeMask & MALLOC_PTR_REGION_RANGE_TYPE)
+ (*m_recorder)(m_task, m_context, MALLOC_PTR_REGION_RANGE_TYPE, &ptrRange, 1);
+
+ if (!(m_typeMask & MALLOC_PTR_IN_USE_RANGE_TYPE)) {
+ m_coalescedSpans.clear();
+ return;
+ }
+
+ Vector<vm_range_t, 1024> allocatedPointers;
+ for (size_t i = 0; i < m_coalescedSpans.size(); ++i) {
+ Span *theSpan = m_coalescedSpans[i];
+ if (theSpan->free)
+ continue;
+
+ vm_address_t spanStartAddress = theSpan->start << kPageShift;
+ vm_size_t spanSizeInBytes = theSpan->length * kPageSize;
+
+ if (!theSpan->sizeclass) {
+ // If it's an allocated large object span, mark it as in use
+ if (!m_freeObjectFinder.isFreeObject(spanStartAddress))
+ allocatedPointers.append((vm_range_t){spanStartAddress, spanSizeInBytes});
+ } else {
+ const size_t objectSize = ByteSizeForClass(theSpan->sizeclass);
+
+ // Mark each allocated small object within the span as in use
+ const vm_address_t endOfSpan = spanStartAddress + spanSizeInBytes;
+ for (vm_address_t object = spanStartAddress; object + objectSize <= endOfSpan; object += objectSize) {
+ if (!m_freeObjectFinder.isFreeObject(object))
+ allocatedPointers.append((vm_range_t){object, objectSize});
+ }
+ }
+ }
+
+ (*m_recorder)(m_task, m_context, MALLOC_PTR_IN_USE_RANGE_TYPE, allocatedPointers.data(), allocatedPointers.size());
+
+ m_coalescedSpans.clear();
+ }
+
+ int visit(void* ptr)
+ {
+ if (!ptr)
+ return 1;
+
+ Span* span = m_reader(reinterpret_cast<Span*>(ptr));
+ if (!span || !span->start)
+ return 1;
+
+ if (m_seenPointers.contains(ptr))
+ return span->length;
+ m_seenPointers.add(ptr);
+
+ if (!m_coalescedSpans.size()) {
+ m_coalescedSpans.append(span);
+ return span->length;
+ }
+
+ Span* previousSpan = m_coalescedSpans[m_coalescedSpans.size() - 1];
+ vm_address_t previousSpanStartAddress = previousSpan->start << kPageShift;
+ vm_size_t previousSpanSizeInBytes = previousSpan->length * kPageSize;
+
+ // If the new span is adjacent to the previous span, do nothing for now.
+ vm_address_t spanStartAddress = span->start << kPageShift;
+ if (spanStartAddress == previousSpanStartAddress + previousSpanSizeInBytes) {
+ m_coalescedSpans.append(span);
+ return span->length;
+ }
+
+ // New span is not adjacent to previous span, so record the spans coalesced so far.
+ recordPendingRegions();
+ m_coalescedSpans.append(span);
+
+ return span->length;
+ }
+};
+
+class AdminRegionRecorder {
+ task_t m_task;
+ void* m_context;
+ unsigned m_typeMask;
+ vm_range_recorder_t* m_recorder;
+ const RemoteMemoryReader& m_reader;
+
+ Vector<vm_range_t, 1024> m_pendingRegions;
+
+public:
+ AdminRegionRecorder(task_t task, void* context, unsigned typeMask, vm_range_recorder_t* recorder, const RemoteMemoryReader& reader)
+ : m_task(task)
+ , m_context(context)
+ , m_typeMask(typeMask)
+ , m_recorder(recorder)
+ , m_reader(reader)
+ { }
+
+ void recordRegion(vm_address_t ptr, size_t size)
+ {
+ if (m_typeMask & MALLOC_ADMIN_REGION_RANGE_TYPE)
+ m_pendingRegions.append((vm_range_t){ ptr, size });
+ }
+
+ void visit(void *ptr, size_t size)
+ {
+ recordRegion(reinterpret_cast<vm_address_t>(ptr), size);
+ }
+
+ void recordPendingRegions()
+ {
+ if (m_pendingRegions.size()) {
+ (*m_recorder)(m_task, m_context, MALLOC_ADMIN_REGION_RANGE_TYPE, m_pendingRegions.data(), m_pendingRegions.size());
+ m_pendingRegions.clear();
+ }
+ }
+
+ ~AdminRegionRecorder()
+ {
+ ASSERT(!m_pendingRegions.size());
+ }
+};
+
+kern_return_t FastMallocZone::enumerate(task_t task, void* context, unsigned typeMask, vm_address_t zoneAddress, memory_reader_t reader, vm_range_recorder_t recorder)
+{
+ RemoteMemoryReader memoryReader(task, reader);
+
+ InitSizeClasses();
+
+ FastMallocZone* mzone = memoryReader(reinterpret_cast<FastMallocZone*>(zoneAddress));
+ TCMalloc_PageHeap* pageHeap = memoryReader(mzone->m_pageHeap);
+ TCMalloc_ThreadCache** threadHeapsPointer = memoryReader(mzone->m_threadHeaps);
+ TCMalloc_ThreadCache* threadHeaps = memoryReader(*threadHeapsPointer);
+
+ TCMalloc_Central_FreeListPadded* centralCaches = memoryReader(mzone->m_centralCaches, sizeof(TCMalloc_Central_FreeListPadded) * kNumClasses);
+
+ FreeObjectFinder finder(memoryReader);
+ finder.findFreeObjects(threadHeaps);
+ finder.findFreeObjects(centralCaches, kNumClasses, mzone->m_centralCaches);
+
+ TCMalloc_PageHeap::PageMap* pageMap = &pageHeap->pagemap_;
+ PageMapFreeObjectFinder pageMapFinder(memoryReader, finder);
+ pageMap->visitValues(pageMapFinder, memoryReader);
+
+ PageMapMemoryUsageRecorder usageRecorder(task, context, typeMask, recorder, memoryReader, finder);
+ pageMap->visitValues(usageRecorder, memoryReader);
+ usageRecorder.recordPendingRegions();
+
+ AdminRegionRecorder adminRegionRecorder(task, context, typeMask, recorder, memoryReader);
+ pageMap->visitAllocations(adminRegionRecorder, memoryReader);
+
+ PageHeapAllocator<Span>* spanAllocator = memoryReader(mzone->m_spanAllocator);
+ PageHeapAllocator<TCMalloc_ThreadCache>* pageHeapAllocator = memoryReader(mzone->m_pageHeapAllocator);
+
+ spanAllocator->recordAdministrativeRegions(adminRegionRecorder, memoryReader);
+ pageHeapAllocator->recordAdministrativeRegions(adminRegionRecorder, memoryReader);
+
+ adminRegionRecorder.recordPendingRegions();
+
+ return 0;
+}
+
+size_t FastMallocZone::size(malloc_zone_t*, const void*)
+{
+ return 0;
+}
+
+void* FastMallocZone::zoneMalloc(malloc_zone_t*, size_t)
+{
+ return 0;
+}
+
+void* FastMallocZone::zoneCalloc(malloc_zone_t*, size_t, size_t)
+{
+ return 0;
+}
+
+void FastMallocZone::zoneFree(malloc_zone_t*, void* ptr)
+{
+ // Due to <rdar://problem/5671357> zoneFree may be called by the system free even if the pointer
+ // is not in this zone. When this happens, the pointer being freed was not allocated by any
+ // zone so we need to print a useful error for the application developer.
+ malloc_printf("*** error for object %p: pointer being freed was not allocated\n", ptr);
+}
+
+void* FastMallocZone::zoneRealloc(malloc_zone_t*, void*, size_t)
+{
+ return 0;
+}
+
+
+#undef malloc
+#undef free
+#undef realloc
+#undef calloc
+
+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_LEOPARD) || OS(IOS)
+ , 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher.
+#endif
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) || OS(IOS)
+ , 0, 0, 0, 0 // These members will not be used unless the zone advertises itself as version seven or higher.
+#endif
+
+ };
+}
+
+FastMallocZone::FastMallocZone(TCMalloc_PageHeap* pageHeap, TCMalloc_ThreadCache** threadHeaps, TCMalloc_Central_FreeListPadded* centralCaches, PageHeapAllocator<Span>* spanAllocator, PageHeapAllocator<TCMalloc_ThreadCache>* pageHeapAllocator)
+ : m_pageHeap(pageHeap)
+ , m_threadHeaps(threadHeaps)
+ , m_centralCaches(centralCaches)
+ , m_spanAllocator(spanAllocator)
+ , m_pageHeapAllocator(pageHeapAllocator)
+{
+ memset(&m_zone, 0, sizeof(m_zone));
+ m_zone.version = 4;
+ m_zone.zone_name = "JavaScriptCore FastMalloc";
+ m_zone.size = &FastMallocZone::size;
+ m_zone.malloc = &FastMallocZone::zoneMalloc;
+ m_zone.calloc = &FastMallocZone::zoneCalloc;
+ m_zone.realloc = &FastMallocZone::zoneRealloc;
+ m_zone.free = &FastMallocZone::zoneFree;
+ m_zone.valloc = &FastMallocZone::zoneValloc;
+ m_zone.destroy = &FastMallocZone::zoneDestroy;
+ m_zone.introspect = &jscore_fastmalloc_introspection;
+ malloc_zone_register(&m_zone);
+}
+
+
+void FastMallocZone::init()
+{
+ static FastMallocZone zone(pageheap, &thread_heaps, static_cast<TCMalloc_Central_FreeListPadded*>(central_cache), &span_allocator, &threadheap_allocator);
+}
+
+#endif // OS(DARWIN)
+
+} // namespace WTF
+#endif // WTF_CHANGES
+
+#endif // FORCE_SYSTEM_MALLOC
diff --git a/Source/JavaScriptCore/wtf/FastMalloc.h b/Source/JavaScriptCore/wtf/FastMalloc.h
new file mode 100644
index 000000000..b4f74e47b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/FastMalloc.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 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_FastMalloc_h
+#define WTF_FastMalloc_h
+
+#include "Platform.h"
+#include "PossiblyNull.h"
+#include <stdlib.h>
+#include <new>
+
+namespace WTF {
+
+ // These functions call CRASH() if an allocation fails.
+ void* fastMalloc(size_t);
+ void* fastZeroedMalloc(size_t);
+ 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)
+ : m_data(data)
+ {
+ }
+ TryMallocReturnValue(const TryMallocReturnValue& source)
+ : m_data(source.m_data)
+ {
+ source.m_data = 0;
+ }
+ ~TryMallocReturnValue() { ASSERT(!m_data); }
+ template <typename T> bool getValue(T& data) WARN_UNUSED_RETURN;
+ template <typename T> operator PossiblyNull<T>()
+ {
+ T value;
+ getValue(value);
+ return PossiblyNull<T>(value);
+ }
+ private:
+ mutable void* m_data;
+ };
+
+ template <typename T> bool TryMallocReturnValue::getValue(T& data)
+ {
+ union u { void* data; T target; } res;
+ res.data = m_data;
+ data = res.target;
+ bool returnValue = !!m_data;
+ m_data = 0;
+ return returnValue;
+ }
+
+ TryMallocReturnValue tryFastMalloc(size_t n);
+ TryMallocReturnValue tryFastZeroedMalloc(size_t n);
+ TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size);
+ TryMallocReturnValue tryFastRealloc(void* p, size_t n);
+
+ void fastFree(void*);
+
+#ifndef NDEBUG
+ void fastMallocForbid();
+ void fastMallocAllow();
+#endif
+
+ void releaseFastMallocFreeMemory();
+
+ struct FastMallocStatistics {
+ size_t reservedVMBytes;
+ size_t committedVMBytes;
+ size_t freeListBytes;
+ };
+ FastMallocStatistics fastMallocStatistics();
+
+ // This defines a type which holds an unsigned integer and is the same
+ // size as the minimally aligned memory allocation.
+ typedef unsigned long long AllocAlignmentInteger;
+
+ namespace Internal {
+ enum AllocType { // Start with an unusual number instead of zero, because zero is common.
+ AllocTypeMalloc = 0x375d6750, // Encompasses fastMalloc, fastZeroedMalloc, fastCalloc, fastRealloc.
+ AllocTypeClassNew, // Encompasses class operator new from FastAllocBase.
+ AllocTypeClassNewArray, // Encompasses class operator new[] from FastAllocBase.
+ AllocTypeFastNew, // Encompasses fastNew.
+ AllocTypeFastNewArray, // Encompasses fastNewArray.
+ AllocTypeNew, // Encompasses global operator new.
+ AllocTypeNewArray // Encompasses global operator new[].
+ };
+
+ enum {
+ ValidationPrefix = 0xf00df00d,
+ ValidationSuffix = 0x0badf00d
+ };
+
+ typedef unsigned ValidationTag;
+
+ struct ValidationHeader {
+ AllocType m_type;
+ unsigned m_size;
+ ValidationTag m_prefix;
+ unsigned m_alignment;
+ };
+
+ static const int ValidationBufferSize = sizeof(ValidationHeader) + sizeof(ValidationTag);
+ }
+
+#if ENABLE(WTF_MALLOC_VALIDATION)
+
+ // Malloc validation is a scheme whereby a tag is attached to an
+ // allocation which identifies how it was originally allocated.
+ // This allows us to verify that the freeing operation matches the
+ // allocation operation. If memory is allocated with operator new[]
+ // but freed with free or delete, this system would detect that.
+ // In the implementation here, the tag is an integer prepended to
+ // the allocation memory which is assigned one of the AllocType
+ // enumeration values. An alternative implementation of this
+ // scheme could store the tag somewhere else or ignore it.
+ // Users of FastMalloc don't need to know or care how this tagging
+ // is implemented.
+
+ namespace Internal {
+
+ // Handle a detected alloc/free mismatch. By default this calls CRASH().
+ void fastMallocMatchFailed(void* p);
+
+ inline ValidationHeader* fastMallocValidationHeader(void* p)
+ {
+ return reinterpret_cast<ValidationHeader*>(static_cast<char*>(p) - sizeof(ValidationHeader));
+ }
+
+ inline ValidationTag* fastMallocValidationSuffix(void* p)
+ {
+ ValidationHeader* header = fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(ValidationPrefix))
+ fastMallocMatchFailed(p);
+
+ return reinterpret_cast<ValidationTag*>(static_cast<char*>(p) + header->m_size);
+ }
+
+ // Return the AllocType tag associated with the allocated block p.
+ inline AllocType fastMallocMatchValidationType(void* p)
+ {
+ return fastMallocValidationHeader(p)->m_type;
+ }
+
+ // Set the AllocType tag to be associaged with the allocated block p.
+ inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
+ {
+ fastMallocValidationHeader(p)->m_type = allocType;
+ }
+
+ } // namespace Internal
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateMalloc(void* p, Internal::AllocType allocType)
+ {
+ if (!p)
+ return;
+
+ Internal::setFastMallocMatchValidationType(p, allocType);
+ }
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateFree(void* p, Internal::AllocType)
+ {
+ if (!p)
+ return;
+
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
+ Internal::fastMallocMatchFailed(p);
+
+ if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
+ Internal::fastMallocMatchFailed(p);
+
+ Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc); // Set it to this so that fastFree thinks it's OK.
+ }
+
+ inline void fastMallocValidate(void* p)
+ {
+ if (!p)
+ return;
+
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
+ Internal::fastMallocMatchFailed(p);
+
+ if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
+ Internal::fastMallocMatchFailed(p);
+ }
+
+#else
+
+ inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
+ {
+ }
+
+ inline void fastMallocMatchValidateFree(void*, Internal::AllocType)
+ {
+ }
+
+#endif
+
+} // namespace WTF
+
+using WTF::fastCalloc;
+using WTF::fastFree;
+using WTF::fastMalloc;
+using WTF::fastMallocSize;
+using WTF::fastRealloc;
+using WTF::fastStrDup;
+using WTF::fastZeroedMalloc;
+using WTF::tryFastCalloc;
+using WTF::tryFastMalloc;
+using WTF::tryFastRealloc;
+using WTF::tryFastZeroedMalloc;
+
+#ifndef NDEBUG
+using WTF::fastMallocForbid;
+using WTF::fastMallocAllow;
+#endif
+
+#if COMPILER(GCC) && OS(DARWIN)
+#define WTF_PRIVATE_INLINE __private_extern__ inline __attribute__((always_inline))
+#elif COMPILER(GCC)
+#define WTF_PRIVATE_INLINE inline __attribute__((always_inline))
+#elif COMPILER(MSVC) || COMPILER(RVCT)
+#define WTF_PRIVATE_INLINE __forceinline
+#else
+#define WTF_PRIVATE_INLINE inline
+#endif
+
+#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+
+// 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.
+// But since WebKit code never uses exceptions or nothrow at all, this is probably OK.
+// Long term we will adopt FastAllocBase.h everywhere, and and replace this with
+// debug-only code to make sure we don't use the system malloc via the default operator
+// new by accident.
+
+#if ENABLE(GLOBAL_FASTMALLOC_NEW)
+
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4290) // Disable the C++ exception specification ignored warning.
+#endif
+WTF_PRIVATE_INLINE void* operator new(size_t size) throw (std::bad_alloc) { return fastMalloc(size); }
+WTF_PRIVATE_INLINE void* operator new(size_t size, const std::nothrow_t&) throw() { return fastMalloc(size); }
+WTF_PRIVATE_INLINE void operator delete(void* p) throw() { fastFree(p); }
+WTF_PRIVATE_INLINE void operator delete(void* p, const std::nothrow_t&) throw() { fastFree(p); }
+WTF_PRIVATE_INLINE void* operator new[](size_t size) throw (std::bad_alloc) { return fastMalloc(size); }
+WTF_PRIVATE_INLINE void* operator new[](size_t size, const std::nothrow_t&) throw() { return fastMalloc(size); }
+WTF_PRIVATE_INLINE void operator delete[](void* p) throw() { fastFree(p); }
+WTF_PRIVATE_INLINE void operator delete[](void* p, const std::nothrow_t&) throw() { fastFree(p); }
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+#endif
+
+#endif
+
+#endif /* WTF_FastMalloc_h */
diff --git a/Source/JavaScriptCore/wtf/FixedArray.h b/Source/JavaScriptCore/wtf/FixedArray.h
new file mode 100644
index 000000000..c67d18cda
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/Float32Array.h b/Source/JavaScriptCore/wtf/Float32Array.h
new file mode 100644
index 000000000..230a768aa
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Float32Array.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Float32Array_h
+#define Float32Array_h
+
+#include "TypedArrayBase.h"
+#include <wtf/MathExtras.h>
+
+namespace WTF {
+
+class Float32Array : public TypedArrayBase<float> {
+public:
+ static inline PassRefPtr<Float32Array> create(unsigned length);
+ static inline PassRefPtr<Float32Array> create(const float* array, unsigned length);
+ static inline PassRefPtr<Float32Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<float>* array, unsigned offset) { return TypedArrayBase<float>::set(array, offset); }
+
+ void set(unsigned index, double value)
+ {
+ if (index >= TypedArrayBase<float>::m_length)
+ return;
+ TypedArrayBase<float>::data()[index] = static_cast<float>(value);
+ }
+
+ // Invoked by the indexed getter. Does not perform range checks; caller
+ // is responsible for doing so and returning undefined as necessary.
+ float item(unsigned index) const
+ {
+ ASSERT(index < TypedArrayBase<float>::m_length);
+ float result = TypedArrayBase<float>::data()[index];
+ return result;
+ }
+
+ inline PassRefPtr<Float32Array> subarray(int start) const;
+ inline PassRefPtr<Float32Array> subarray(int start, int end) const;
+
+private:
+ inline Float32Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<float>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isFloatArray() const { return true; }
+};
+
+PassRefPtr<Float32Array> Float32Array::create(unsigned length)
+{
+ return TypedArrayBase<float>::create<Float32Array>(length);
+}
+
+PassRefPtr<Float32Array> Float32Array::create(const float* array, unsigned length)
+{
+ return TypedArrayBase<float>::create<Float32Array>(array, length);
+}
+
+PassRefPtr<Float32Array> Float32Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<float>::create<Float32Array>(buffer, byteOffset, length);
+}
+
+Float32Array::Float32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : TypedArrayBase<float>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Float32Array> Float32Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Float32Array> Float32Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Float32Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Float32Array;
+
+#endif // Float32Array_h
diff --git a/Source/JavaScriptCore/wtf/Float64Array.h b/Source/JavaScriptCore/wtf/Float64Array.h
new file mode 100644
index 000000000..46713556c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Float64Array.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 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 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 Float64Array_h
+#define Float64Array_h
+
+#include "TypedArrayBase.h"
+#include <wtf/MathExtras.h>
+
+namespace WTF {
+
+class Float64Array : public TypedArrayBase<double> {
+public:
+ static inline PassRefPtr<Float64Array> create(unsigned length);
+ static inline PassRefPtr<Float64Array> create(const double* array, unsigned length);
+ static inline PassRefPtr<Float64Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<double>* array, unsigned offset) { return TypedArrayBase<double>::set(array, offset); }
+
+ void set(unsigned index, double value)
+ {
+ if (index >= TypedArrayBase<double>::m_length)
+ return;
+ TypedArrayBase<double>::data()[index] = static_cast<double>(value);
+ }
+
+ // Invoked by the indexed getter. Does not perform range checks; caller
+ // is responsible for doing so and returning undefined as necessary.
+ double item(unsigned index) const
+ {
+ ASSERT(index < TypedArrayBase<double>::m_length);
+ double result = TypedArrayBase<double>::data()[index];
+ return result;
+ }
+
+ inline PassRefPtr<Float64Array> subarray(int start) const;
+ inline PassRefPtr<Float64Array> subarray(int start, int end) const;
+
+private:
+ inline Float64Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<double>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isDoubleArray() const { return true; }
+};
+
+PassRefPtr<Float64Array> Float64Array::create(unsigned length)
+{
+ return TypedArrayBase<double>::create<Float64Array>(length);
+}
+
+PassRefPtr<Float64Array> Float64Array::create(const double* array, unsigned length)
+{
+ return TypedArrayBase<double>::create<Float64Array>(array, length);
+}
+
+PassRefPtr<Float64Array> Float64Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<double>::create<Float64Array>(buffer, byteOffset, length);
+}
+
+Float64Array::Float64Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : TypedArrayBase<double>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Float64Array> Float64Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Float64Array> Float64Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Float64Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Float64Array;
+
+#endif // Float64Array_h
diff --git a/Source/JavaScriptCore/wtf/Forward.h b/Source/JavaScriptCore/wtf/Forward.h
new file mode 100644
index 000000000..3c97849cc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Forward.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006, 2009, 2011 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_Forward_h
+#define WTF_Forward_h
+
+#include <stddef.h>
+
+namespace WTF {
+ template<typename T> class Function;
+ 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 ArrayBuffer;
+ class ArrayBufferView;
+ class AtomicString;
+ class AtomicStringImpl;
+ class CString;
+ class Decoder;
+ class Encoder;
+ class Float32Array;
+ class Float64Array;
+ class Int8Array;
+ class Int16Array;
+ class Int32Array;
+ class String;
+ template <typename T> class StringBuffer;
+ class StringBuilder;
+ class StringImpl;
+ class Uint8Array;
+ class Uint16Array;
+ class Uint32Array;
+}
+
+using WTF::Function;
+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::ArrayBuffer;
+using WTF::ArrayBufferView;
+using WTF::AtomicString;
+using WTF::AtomicStringImpl;
+using WTF::CString;
+using WTF::Encoder;
+using WTF::Decoder;
+using WTF::Float32Array;
+using WTF::Float64Array;
+using WTF::Int8Array;
+using WTF::Int16Array;
+using WTF::Int32Array;
+using WTF::String;
+using WTF::StringBuffer;
+using WTF::StringBuilder;
+using WTF::StringImpl;
+using WTF::Uint8Array;
+using WTF::Uint16Array;
+using WTF::Uint32Array;
+
+#endif // WTF_Forward_h
diff --git a/Source/JavaScriptCore/wtf/Functional.h b/Source/JavaScriptCore/wtf/Functional.h
new file mode 100644
index 000000000..86d6203cf
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Functional.h
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2011 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_Functional_h
+#define WTF_Functional_h
+
+#include "Assertions.h"
+#include "PassRefPtr.h"
+#include "RefPtr.h"
+#include "ThreadSafeRefCounted.h"
+
+#if PLATFORM(MAC) && COMPILER_SUPPORTS(BLOCKS)
+#include <objc/objc-runtime.h>
+#endif
+
+namespace WTF {
+
+// Functional.h provides a very simple way to bind a function pointer and arguments together into a function object
+// that can be stored, copied and invoked, similar to how boost::bind and std::bind in C++11.
+
+// Helper class template to determine whether a given type has ref and deref member functions
+// with the right type signature.
+template<typename T>
+class HasRefAndDeref {
+ typedef char YesType;
+ struct NoType {
+ char padding[8];
+ };
+
+ struct BaseMixin {
+ void deref();
+ void ref();
+ };
+
+ struct Base : public T, public BaseMixin { };
+
+ template<typename U, U> struct
+ TypeChecker { };
+
+ template<typename U>
+ static NoType refCheck(U*, TypeChecker<void (BaseMixin::*)(), &U::ref>* = 0);
+ static YesType refCheck(...);
+
+ template<typename U>
+ static NoType derefCheck(U*, TypeChecker<void (BaseMixin::*)(), &U::deref>* = 0);
+ static YesType derefCheck(...);
+
+public:
+ static const bool value = sizeof(refCheck(static_cast<Base*>(0))) == sizeof(YesType) && sizeof(derefCheck(static_cast<Base*>(0))) == sizeof(YesType);
+};
+
+// A FunctionWrapper is a class template that can wrap a function pointer or a member function pointer and
+// provide a unified interface for calling that function.
+template<typename>
+class FunctionWrapper;
+
+template<typename R>
+class FunctionWrapper<R (*)()> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = false;
+
+ explicit FunctionWrapper(R (*function)())
+ : m_function(function)
+ {
+ }
+
+ R operator()()
+ {
+ return m_function();
+ }
+
+private:
+ R (*m_function)();
+};
+
+template<typename R, typename P1>
+class FunctionWrapper<R (*)(P1)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = false;
+
+ explicit FunctionWrapper(R (*function)(P1))
+ : m_function(function)
+ {
+ }
+
+ R operator()(P1 p1)
+ {
+ return m_function(p1);
+ }
+
+private:
+ R (*m_function)(P1);
+};
+
+template<typename R, typename P1, typename P2>
+class FunctionWrapper<R (*)(P1, P2)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = false;
+
+ explicit FunctionWrapper(R (*function)(P1, P2))
+ : m_function(function)
+ {
+ }
+
+ R operator()(P1 p1, P2 p2)
+ {
+ return m_function(p1, p2);
+ }
+
+private:
+ R (*m_function)(P1, P2);
+};
+
+template<typename R, typename C>
+class FunctionWrapper<R (C::*)()> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)())
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c)
+ {
+ return (c->*m_function)();
+ }
+
+private:
+ R (C::*m_function)();
+};
+
+template<typename R, typename C, typename P1>
+class FunctionWrapper<R (C::*)(P1)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)(P1))
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c, P1 p1)
+ {
+ return (c->*m_function)(p1);
+ }
+
+private:
+ R (C::*m_function)(P1);
+};
+
+template<typename R, typename C, typename P1, typename P2>
+class FunctionWrapper<R (C::*)(P1, P2)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)(P1, P2))
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c, P1 p1, P2 p2)
+ {
+ return (c->*m_function)(p1, p2);
+ }
+
+private:
+ R (C::*m_function)(P1, P2);
+};
+
+template<typename R, typename C, typename P1, typename P2, typename P3>
+class FunctionWrapper<R (C::*)(P1, P2, P3)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)(P1, P2, P3))
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c, P1 p1, P2 p2, P3 p3)
+ {
+ return (c->*m_function)(p1, p2, p3);
+ }
+
+private:
+ R (C::*m_function)(P1, P2, P3);
+};
+
+template<typename R, typename C, typename P1, typename P2, typename P3, typename P4>
+class FunctionWrapper<R (C::*)(P1, P2, P3, P4)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)(P1, P2, P3, P4))
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c, P1 p1, P2 p2, P3 p3, P4 p4)
+ {
+ return (c->*m_function)(p1, p2, p3, p4);
+ }
+
+private:
+ R (C::*m_function)(P1, P2, P3, P4);
+};
+
+template<typename R, typename C, typename P1, typename P2, typename P3, typename P4, typename P5>
+class FunctionWrapper<R (C::*)(P1, P2, P3, P4, P5)> {
+public:
+ typedef R ResultType;
+ static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;
+
+ explicit FunctionWrapper(R (C::*function)(P1, P2, P3, P4, P5))
+ : m_function(function)
+ {
+ }
+
+ R operator()(C* c, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+ {
+ return (c->*m_function)(p1, p2, p3, p4, p5);
+ }
+
+private:
+ R (C::*m_function)(P1, P2, P3, P4, P5);
+};
+
+template<typename T, bool shouldRefAndDeref> struct RefAndDeref {
+ static void ref(T) { }
+ static void deref(T) { }
+};
+
+template<typename T> struct RefAndDeref<T*, true> {
+ static void ref(T* t) { t->ref(); }
+ static void deref(T* t) { t->deref(); }
+};
+
+template<typename T> struct ParamStorageTraits {
+ typedef T StorageType;
+
+ static StorageType wrap(const T& value) { return value; }
+ static const T& unwrap(const StorageType& value) { return value; }
+};
+
+template<typename T> struct ParamStorageTraits<PassRefPtr<T> > {
+ typedef RefPtr<T> StorageType;
+
+ static StorageType wrap(PassRefPtr<T> value) { return value; }
+ static T* unwrap(const StorageType& value) { return value.get(); }
+};
+
+template<typename T> struct ParamStorageTraits<RefPtr<T> > {
+ typedef RefPtr<T> StorageType;
+
+ static StorageType wrap(RefPtr<T> value) { return value.release(); }
+ static T* unwrap(const StorageType& value) { return value.get(); }
+};
+
+
+template<typename> class RetainPtr;
+
+template<typename T> struct ParamStorageTraits<RetainPtr<T> > {
+ typedef RetainPtr<T> StorageType;
+
+ static StorageType wrap(const RetainPtr<T>& value) { return value; }
+ static typename RetainPtr<T>::PtrType unwrap(const StorageType& value) { return value.get(); }
+};
+
+class FunctionImplBase : public ThreadSafeRefCounted<FunctionImplBase> {
+public:
+ virtual ~FunctionImplBase() { }
+};
+
+template<typename>
+class FunctionImpl;
+
+template<typename R>
+class FunctionImpl<R ()> : public FunctionImplBase {
+public:
+ virtual R operator()() = 0;
+};
+
+template<typename FunctionWrapper, typename FunctionType>
+class BoundFunctionImpl;
+
+template<typename FunctionWrapper, typename R>
+class BoundFunctionImpl<FunctionWrapper, R ()> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ explicit BoundFunctionImpl(FunctionWrapper functionWrapper)
+ : m_functionWrapper(functionWrapper)
+ {
+ }
+
+ virtual R operator()()
+ {
+ return m_functionWrapper();
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+};
+
+template<typename FunctionWrapper, typename R, typename P1>
+class BoundFunctionImpl<FunctionWrapper, R (P1)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual R operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+};
+
+template<typename FunctionWrapper, typename R, typename P1, typename P2>
+class BoundFunctionImpl<FunctionWrapper, R (P1, P2)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ , m_p2(ParamStorageTraits<P2>::wrap(p2))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual typename FunctionWrapper::ResultType operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+ typename ParamStorageTraits<P2>::StorageType m_p2;
+};
+
+template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3>
+class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ , m_p2(ParamStorageTraits<P2>::wrap(p2))
+ , m_p3(ParamStorageTraits<P3>::wrap(p3))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual typename FunctionWrapper::ResultType operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+ typename ParamStorageTraits<P2>::StorageType m_p2;
+ typename ParamStorageTraits<P3>::StorageType m_p3;
+};
+
+template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4>
+class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ , m_p2(ParamStorageTraits<P2>::wrap(p2))
+ , m_p3(ParamStorageTraits<P3>::wrap(p3))
+ , m_p4(ParamStorageTraits<P4>::wrap(p4))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual typename FunctionWrapper::ResultType operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+ typename ParamStorageTraits<P2>::StorageType m_p2;
+ typename ParamStorageTraits<P3>::StorageType m_p3;
+ typename ParamStorageTraits<P4>::StorageType m_p4;
+};
+
+template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
+class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4, P5)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ , m_p2(ParamStorageTraits<P2>::wrap(p2))
+ , m_p3(ParamStorageTraits<P3>::wrap(p3))
+ , m_p4(ParamStorageTraits<P4>::wrap(p4))
+ , m_p5(ParamStorageTraits<P5>::wrap(p5))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual typename FunctionWrapper::ResultType operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4), ParamStorageTraits<P5>::unwrap(m_p5));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+ typename ParamStorageTraits<P2>::StorageType m_p2;
+ typename ParamStorageTraits<P3>::StorageType m_p3;
+ typename ParamStorageTraits<P4>::StorageType m_p4;
+ typename ParamStorageTraits<P5>::StorageType m_p5;
+};
+
+template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
+class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4, P5, P6)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
+public:
+ BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6)
+ : m_functionWrapper(functionWrapper)
+ , m_p1(ParamStorageTraits<P1>::wrap(p1))
+ , m_p2(ParamStorageTraits<P2>::wrap(p2))
+ , m_p3(ParamStorageTraits<P3>::wrap(p3))
+ , m_p4(ParamStorageTraits<P4>::wrap(p4))
+ , m_p5(ParamStorageTraits<P5>::wrap(p5))
+ , m_p6(ParamStorageTraits<P6>::wrap(p6))
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
+ }
+
+ ~BoundFunctionImpl()
+ {
+ RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
+ }
+
+ virtual typename FunctionWrapper::ResultType operator()()
+ {
+ return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4), ParamStorageTraits<P5>::unwrap(m_p5), ParamStorageTraits<P6>::unwrap(m_p6));
+ }
+
+private:
+ FunctionWrapper m_functionWrapper;
+ typename ParamStorageTraits<P1>::StorageType m_p1;
+ typename ParamStorageTraits<P2>::StorageType m_p2;
+ typename ParamStorageTraits<P3>::StorageType m_p3;
+ typename ParamStorageTraits<P4>::StorageType m_p4;
+ typename ParamStorageTraits<P5>::StorageType m_p5;
+ typename ParamStorageTraits<P6>::StorageType m_p6;
+};
+
+class FunctionBase {
+public:
+ bool isNull() const
+ {
+ return !m_impl;
+ }
+
+protected:
+ FunctionBase()
+ {
+ }
+
+ explicit FunctionBase(PassRefPtr<FunctionImplBase> impl)
+ : m_impl(impl)
+ {
+ }
+
+ template<typename FunctionType> FunctionImpl<FunctionType>* impl() const
+ {
+ return static_cast<FunctionImpl<FunctionType>*>(m_impl.get());
+ }
+
+private:
+ RefPtr<FunctionImplBase> m_impl;
+};
+
+template<typename>
+class Function;
+
+template<typename R>
+class Function<R ()> : public FunctionBase {
+public:
+ Function()
+ {
+ }
+
+ Function(PassRefPtr<FunctionImpl<R ()> > impl)
+ : FunctionBase(impl)
+ {
+ }
+
+ R operator()() const
+ {
+ ASSERT(!isNull());
+
+ return impl<R ()>()->operator()();
+ }
+
+#if PLATFORM(MAC) && COMPILER_SUPPORTS(BLOCKS)
+ typedef void (^BlockType)();
+ operator BlockType() const
+ {
+ // Declare a RefPtr here so we'll be sure that the underlying FunctionImpl object's
+ // lifecycle is managed correctly.
+ RefPtr<FunctionImpl<R ()> > functionImpl = impl<R ()>();
+ BlockType block = ^{
+ functionImpl->operator()();
+ };
+
+ // This is equivalent to:
+ //
+ // return [[block copy] autorelease];
+ //
+ // We're using manual objc_msgSend calls here because we don't want to make the entire
+ // file Objective-C. It's useful to be able to implicitly convert a Function to
+ // a block even in C++ code, since that allows us to do things like:
+ //
+ // dispatch_async(queue, bind(...));
+ //
+ id copiedBlock = objc_msgSend((id)block, sel_registerName("copy"));
+ id autoreleasedBlock = objc_msgSend(copiedBlock, sel_registerName("autorelease"));
+ return (BlockType)autoreleasedBlock;
+ }
+#endif
+};
+
+template<typename FunctionType>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType ()>(FunctionWrapper<FunctionType>(function))));
+}
+
+template<typename FunctionType, typename A1>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1)>(FunctionWrapper<FunctionType>(function), a1)));
+}
+
+template<typename FunctionType, typename A1, typename A2>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2)>(FunctionWrapper<FunctionType>(function), a1, a2)));
+}
+
+template<typename FunctionType, typename A1, typename A2, typename A3>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3)>(FunctionWrapper<FunctionType>(function), a1, a2, a3)));
+}
+
+template<typename FunctionType, typename A1, typename A2, typename A3, typename A4>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4)));
+}
+
+template<typename FunctionType, typename A1, typename A2, typename A3, typename A4, typename A5>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4, A5)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4, a5)));
+}
+
+template<typename FunctionType, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
+{
+ return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4, A5, A6)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4, a5, a6)));
+}
+
+}
+
+using WTF::Function;
+using WTF::bind;
+
+#endif // WTF_Functional_h
diff --git a/Source/JavaScriptCore/wtf/GetPtr.h b/Source/JavaScriptCore/wtf/GetPtr.h
new file mode 100644
index 000000000..25a0e6d9b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/GetPtr.h
@@ -0,0 +1,33 @@
+/*
+ * 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 WTF_GetPtr_h
+#define WTF_GetPtr_h
+
+namespace WTF {
+
+ template <typename T> inline T* getPtr(T* p)
+ {
+ return p;
+ }
+
+} // namespace WTF
+
+#endif // WTF_GetPtr_h
diff --git a/Source/JavaScriptCore/wtf/HashCountedSet.h b/Source/JavaScriptCore/wtf/HashCountedSet.h
new file mode 100644
index 000000000..b97d8c8fd
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashCountedSet.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 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 WTF_HashCountedSet_h
+#define WTF_HashCountedSet_h
+
+#include "Assertions.h"
+#include "HashMap.h"
+#include "Vector.h"
+
+namespace WTF {
+
+ template<typename Value, typename HashFunctions = typename DefaultHash<Value>::Hash,
+ typename Traits = HashTraits<Value> > class HashCountedSet {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef HashMap<Value, unsigned, HashFunctions, Traits> ImplType;
+ public:
+ typedef Value ValueType;
+ typedef typename ImplType::iterator iterator;
+ typedef typename ImplType::const_iterator const_iterator;
+
+ HashCountedSet() {}
+
+ int size() const;
+ int capacity() const;
+ bool isEmpty() const;
+
+ // Iterators iterate over pairs of values and counts.
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator find(const ValueType&);
+ const_iterator find(const ValueType&) const;
+ 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.
+ std::pair<iterator, bool> add(const ValueType&);
+
+ // 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.
+ void removeAll(iterator);
+ void removeAll(const ValueType&);
+
+ // Clears the whole set.
+ void clear();
+
+ private:
+ ImplType m_impl;
+ };
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline int HashCountedSet<Value, HashFunctions, Traits>::size() const
+ {
+ return m_impl.size();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline int HashCountedSet<Value, HashFunctions, Traits>::capacity() const
+ {
+ return m_impl.capacity();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline bool HashCountedSet<Value, HashFunctions, Traits>::isEmpty() const
+ {
+ return size() == 0;
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::begin()
+ {
+ return m_impl.begin();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::end()
+ {
+ return m_impl.end();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::begin() const
+ {
+ return m_impl.begin();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::end() const
+ {
+ return m_impl.end();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::find(const ValueType& value)
+ {
+ return m_impl.find(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::find(const ValueType& value) const
+ {
+ return m_impl.find(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline bool HashCountedSet<Value, HashFunctions, Traits>::contains(const ValueType& value) const
+ {
+ return m_impl.contains(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline unsigned HashCountedSet<Value, HashFunctions, Traits>::count(const ValueType& value) const
+ {
+ return m_impl.get(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline std::pair<typename HashCountedSet<Value, HashFunctions, Traits>::iterator, bool> HashCountedSet<Value, HashFunctions, Traits>::add(const ValueType &value)
+ {
+ pair<iterator, bool> result = m_impl.add(value, 0);
+ ++result.first->second;
+ return result;
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(const ValueType& value)
+ {
+ return remove(find(value));
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(iterator it)
+ {
+ if (it == end())
+ return false;
+
+ unsigned oldVal = it->second;
+ ASSERT(oldVal);
+ unsigned newVal = oldVal - 1;
+ if (newVal) {
+ it->second = newVal;
+ return false;
+ }
+
+ m_impl.remove(it);
+ return true;
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline void HashCountedSet<Value, HashFunctions, Traits>::removeAll(const ValueType& value)
+ {
+ removeAll(find(value));
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline void HashCountedSet<Value, HashFunctions, Traits>::removeAll(iterator it)
+ {
+ if (it == end())
+ return;
+
+ m_impl.remove(it);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline void HashCountedSet<Value, HashFunctions, Traits>::clear()
+ {
+ m_impl.clear();
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits, typename VectorType>
+ inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, VectorType& vector)
+ {
+ typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
+
+ vector.resize(collection.size());
+
+ iterator it = collection.begin();
+ iterator end = collection.end();
+ for (unsigned i = 0; it != end; ++it, ++i)
+ vector[i] = *it;
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, Vector<Value>& vector)
+ {
+ typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
+
+ vector.resize(collection.size());
+
+ iterator it = collection.begin();
+ iterator end = collection.end();
+ for (unsigned i = 0; it != end; ++it, ++i)
+ vector[i] = (*it).first;
+ }
+
+
+} // namespace khtml
+
+using WTF::HashCountedSet;
+
+#endif /* WTF_HashCountedSet_h */
diff --git a/Source/JavaScriptCore/wtf/HashFunctions.h b/Source/JavaScriptCore/wtf/HashFunctions.h
new file mode 100644
index 000000000..2c66a2d9f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashFunctions.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 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 WTF_HashFunctions_h
+#define WTF_HashFunctions_h
+
+#include "RefPtr.h"
+#include <stdint.h>
+
+namespace WTF {
+
+ template<size_t size> struct IntTypes;
+ template<> struct IntTypes<1> { typedef int8_t SignedType; typedef uint8_t UnsignedType; };
+ template<> struct IntTypes<2> { typedef int16_t SignedType; typedef uint16_t UnsignedType; };
+ template<> struct IntTypes<4> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
+ template<> struct IntTypes<8> { typedef int64_t SignedType; typedef uint64_t UnsignedType; };
+
+ // integer hash function
+
+ // Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
+ inline unsigned intHash(uint8_t key8)
+ {
+ unsigned key = key8;
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+ }
+
+ // Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
+ inline unsigned intHash(uint16_t key16)
+ {
+ unsigned key = key16;
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+ }
+
+ // Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
+ inline unsigned intHash(uint32_t key)
+ {
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+ }
+
+ // Thomas Wang's 64 bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
+ inline unsigned intHash(uint64_t key)
+ {
+ key += ~(key << 32);
+ key ^= (key >> 22);
+ key += ~(key << 13);
+ key ^= (key >> 8);
+ key += (key << 3);
+ key ^= (key >> 15);
+ key += ~(key << 27);
+ key ^= (key >> 31);
+ return static_cast<unsigned>(key);
+ }
+
+ template<typename T> struct IntHash {
+ static unsigned hash(T key) { return intHash(static_cast<typename IntTypes<sizeof(T)>::UnsignedType>(key)); }
+ static bool equal(T a, T b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ template<typename T> struct FloatHash {
+ static unsigned hash(T key)
+ {
+ union {
+ T key;
+ typename IntTypes<sizeof(T)>::UnsignedType bits;
+ } u;
+ u.key = key;
+ return intHash(u.bits);
+ }
+ static bool equal(T a, T b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ // pointer identity hash function
+
+ template<typename T> struct PtrHash {
+ static unsigned hash(T key)
+ {
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4244) // work around what seems to be a bug in MSVC's conversion warnings
+#endif
+ return IntHash<uintptr_t>::hash(reinterpret_cast<uintptr_t>(key));
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+ }
+ static bool equal(T a, T b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+ template<typename P> struct PtrHash<RefPtr<P> > : PtrHash<P*> {
+ using PtrHash<P*>::hash;
+ static unsigned hash(const RefPtr<P>& key) { return hash(key.get()); }
+ using PtrHash<P*>::equal;
+ static bool equal(const RefPtr<P>& a, const RefPtr<P>& b) { return a == b; }
+ static bool equal(P* a, const RefPtr<P>& b) { return a == b; }
+ static bool equal(const RefPtr<P>& a, P* b) { return a == b; }
+ };
+
+ // default hash function for each type
+
+ template<typename T> struct DefaultHash;
+
+ template<typename T, typename U> struct PairHash {
+ static unsigned hash(const std::pair<T, U>& p)
+ {
+ return intHash((static_cast<uint64_t>(DefaultHash<T>::Hash::hash(p.first)) << 32 | DefaultHash<U>::Hash::hash(p.second)));
+ }
+ static bool equal(const std::pair<T, U>& a, const std::pair<T, U>& b)
+ {
+ return DefaultHash<T>::Hash::equal(a.first, b.first) && DefaultHash<U>::Hash::equal(a.second, b.second);
+ }
+ static const bool safeToCompareToEmptyOrDeleted = DefaultHash<T>::Hash::safeToCompareToEmptyOrDeleted
+ && DefaultHash<U>::Hash::safeToCompareToEmptyOrDeleted;
+ };
+
+ // make IntHash the default hash function for many integer types
+
+ template<> struct DefaultHash<short> { typedef IntHash<unsigned> Hash; };
+ template<> struct DefaultHash<unsigned short> { typedef IntHash<unsigned> Hash; };
+ template<> struct DefaultHash<int> { typedef IntHash<unsigned> Hash; };
+ template<> struct DefaultHash<unsigned> { typedef IntHash<unsigned> Hash; };
+ template<> struct DefaultHash<long> { typedef IntHash<unsigned long> Hash; };
+ template<> struct DefaultHash<unsigned long> { typedef IntHash<unsigned long> Hash; };
+ template<> struct DefaultHash<long long> { typedef IntHash<unsigned long long> Hash; };
+ template<> struct DefaultHash<unsigned long long> { typedef IntHash<unsigned long long> Hash; };
+
+#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
+ template<> struct DefaultHash<wchar_t> { typedef IntHash<wchar_t> Hash; };
+#endif
+
+ template<> struct DefaultHash<float> { typedef FloatHash<float> Hash; };
+ template<> struct DefaultHash<double> { typedef FloatHash<double> Hash; };
+
+ // make PtrHash the default hash function for pointer types that don't specialize
+
+ template<typename P> struct DefaultHash<P*> { typedef PtrHash<P*> Hash; };
+ template<typename P> struct DefaultHash<RefPtr<P> > { typedef PtrHash<RefPtr<P> > Hash; };
+
+ template<typename T, typename U> struct DefaultHash<std::pair<T, U> > { typedef PairHash<T, U> Hash; };
+
+} // namespace WTF
+
+using WTF::DefaultHash;
+using WTF::IntHash;
+using WTF::PtrHash;
+
+#endif // WTF_HashFunctions_h
diff --git a/Source/JavaScriptCore/wtf/HashIterators.h b/Source/JavaScriptCore/wtf/HashIterators.h
new file mode 100644
index 000000000..6afa2fa57
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashIterators.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2007 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_HashIterators_h
+#define WTF_HashIterators_h
+
+namespace WTF {
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator;
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstValuesIterator;
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableKeysIterator;
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableValuesIterator;
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > {
+ private:
+ typedef std::pair<KeyType, MappedType> ValueType;
+ public:
+ typedef HashTableConstKeysIterator<HashTableType, KeyType, MappedType> Keys;
+ typedef HashTableConstValuesIterator<HashTableType, KeyType, MappedType> Values;
+
+ HashTableConstIteratorAdapter() {}
+ HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
+
+ const ValueType* get() const { return (const ValueType*)m_impl.get(); }
+ const ValueType& operator*() const { return *get(); }
+ const ValueType* operator->() const { return get(); }
+
+ HashTableConstIteratorAdapter& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ Keys keys() { return Keys(*this); }
+ Values values() { return Values(*this); }
+
+ typename HashTableType::const_iterator m_impl;
+ };
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > {
+ private:
+ typedef std::pair<KeyType, MappedType> ValueType;
+ public:
+ typedef HashTableKeysIterator<HashTableType, KeyType, MappedType> Keys;
+ typedef HashTableValuesIterator<HashTableType, KeyType, MappedType> Values;
+
+ HashTableIteratorAdapter() {}
+ HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
+
+ ValueType* get() const { return (ValueType*)m_impl.get(); }
+ ValueType& operator*() const { return *get(); }
+ ValueType* operator->() const { return get(); }
+
+ HashTableIteratorAdapter& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
+ typename HashTableType::const_iterator i = m_impl;
+ return i;
+ }
+
+ Keys keys() { return Keys(*this); }
+ Values values() { return Values(*this); }
+
+ typename HashTableType::iterator m_impl;
+ };
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator {
+ private:
+ typedef HashTableConstIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > ConstIterator;
+
+ public:
+ HashTableConstKeysIterator(const ConstIterator& impl) : m_impl(impl) {}
+
+ const KeyType* get() const { return &(m_impl.get()->first); }
+ const KeyType& operator*() const { return *get(); }
+ const KeyType* operator->() const { return get(); }
+
+ HashTableConstKeysIterator& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ ConstIterator m_impl;
+ };
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstValuesIterator {
+ private:
+ typedef HashTableConstIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > ConstIterator;
+
+ public:
+ HashTableConstValuesIterator(const ConstIterator& impl) : m_impl(impl) {}
+
+ const MappedType* get() const { return &(m_impl.get()->second); }
+ const MappedType& operator*() const { return *get(); }
+ const MappedType* operator->() const { return get(); }
+
+ HashTableConstValuesIterator& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ ConstIterator m_impl;
+ };
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableKeysIterator {
+ private:
+ typedef HashTableIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > Iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > ConstIterator;
+
+ public:
+ HashTableKeysIterator(const Iterator& impl) : m_impl(impl) {}
+
+ KeyType* get() const { return &(m_impl.get()->first); }
+ KeyType& operator*() const { return *get(); }
+ KeyType* operator->() const { return get(); }
+
+ HashTableKeysIterator& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ operator HashTableConstKeysIterator<HashTableType, KeyType, MappedType>() {
+ ConstIterator i = m_impl;
+ return i;
+ }
+
+ Iterator m_impl;
+ };
+
+ template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableValuesIterator {
+ private:
+ typedef HashTableIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > Iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, std::pair<KeyType, MappedType> > ConstIterator;
+
+ public:
+ HashTableValuesIterator(const Iterator& impl) : m_impl(impl) {}
+
+ MappedType* get() const { return &(m_impl.get()->second); }
+ MappedType& operator*() const { return *get(); }
+ MappedType* operator->() const { return get(); }
+
+ HashTableValuesIterator& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ operator HashTableConstValuesIterator<HashTableType, KeyType, MappedType>() {
+ ConstIterator i = m_impl;
+ return i;
+ }
+
+ Iterator m_impl;
+ };
+
+ template<typename T, typename U, typename V>
+ inline bool operator==(const HashTableConstKeysIterator<T, U, V>& a, const HashTableConstKeysIterator<T, U, V>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator!=(const HashTableConstKeysIterator<T, U, V>& a, const HashTableConstKeysIterator<T, U, V>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator==(const HashTableConstValuesIterator<T, U, V>& a, const HashTableConstValuesIterator<T, U, V>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator!=(const HashTableConstValuesIterator<T, U, V>& a, const HashTableConstValuesIterator<T, U, V>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator==(const HashTableKeysIterator<T, U, V>& a, const HashTableKeysIterator<T, U, V>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator!=(const HashTableKeysIterator<T, U, V>& a, const HashTableKeysIterator<T, U, V>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator==(const HashTableValuesIterator<T, U, V>& a, const HashTableValuesIterator<T, U, V>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool operator!=(const HashTableValuesIterator<T, U, V>& a, const HashTableValuesIterator<T, U, V>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+
+} // namespace WTF
+
+#endif // WTF_HashIterators_h
diff --git a/Source/JavaScriptCore/wtf/HashMap.h b/Source/JavaScriptCore/wtf/HashMap.h
new file mode 100644
index 000000000..13e6d496d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashMap.h
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 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_HashMap_h
+#define WTF_HashMap_h
+
+#include "HashTable.h"
+
+namespace WTF {
+
+ template<typename PairType> struct PairFirstExtractor;
+
+ template<typename T> struct ReferenceTypeMaker {
+ typedef T& ReferenceType;
+ };
+ template<typename T> struct ReferenceTypeMaker<T&> {
+ typedef T& ReferenceType;
+ };
+
+ template<typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
+ typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg> >
+ class HashMap {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef KeyTraitsArg KeyTraits;
+ typedef MappedTraitsArg MappedTraits;
+ typedef PairHashTraits<KeyTraits, MappedTraits> ValueTraits;
+
+ public:
+ typedef typename KeyTraits::TraitType KeyType;
+ typedef typename MappedTraits::TraitType MappedType;
+ typedef typename ValueTraits::TraitType ValueType;
+
+ private:
+ typedef typename MappedTraits::PassInType MappedPassInType;
+ typedef typename MappedTraits::PassOutType MappedPassOutType;
+ typedef typename MappedTraits::PeekType MappedPeekType;
+
+ typedef typename ReferenceTypeMaker<MappedPassInType>::ReferenceType MappedPassInReferenceType;
+
+ typedef HashArg HashFunctions;
+
+ typedef HashTable<KeyType, ValueType, PairFirstExtractor<ValueType>,
+ HashFunctions, ValueTraits, KeyTraits> HashTableType;
+
+ class HashMapKeysProxy;
+ class HashMapValuesProxy;
+
+ public:
+ typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
+
+ public:
+ void swap(HashMap&);
+
+ int size() const;
+ int capacity() const;
+ bool isEmpty() const;
+
+ // iterators iterate over pairs of keys and values
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ HashMapKeysProxy& keys() { return static_cast<HashMapKeysProxy&>(*this); }
+ const HashMapKeysProxy& keys() const { return static_cast<const HashMapKeysProxy&>(*this); }
+
+ HashMapValuesProxy& values() { return static_cast<HashMapValuesProxy&>(*this); }
+ const HashMapValuesProxy& values() const { return static_cast<const HashMapValuesProxy&>(*this); }
+
+ iterator find(const KeyType&);
+ const_iterator find(const KeyType&) const;
+ bool contains(const KeyType&) const;
+ MappedPeekType get(const KeyType&) const;
+
+ // replaces value but not key if key is already present
+ // return value is a pair of the iterator to the key location,
+ // and a boolean that's true if a new value was actually added
+ pair<iterator, bool> set(const KeyType&, MappedPassInType);
+
+ // does nothing if key is already present
+ // return value is a pair of the iterator to the key location,
+ // and a boolean that's true if a new value was actually added
+ pair<iterator, bool> add(const KeyType&, MappedPassInType);
+
+ void remove(const KeyType&);
+ void remove(iterator);
+ void clear();
+
+ MappedPassOutType take(const KeyType&); // efficient combination of get with remove
+
+ // An alternate version of find() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion. HashTranslator
+ // 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> bool contains(const T&) const;
+
+ // An alternate version of add() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion if the object is already
+ // in the table. HashTranslator must have the following function members:
+ // static unsigned hash(const T&);
+ // static bool equal(const ValueType&, const T&);
+ // static translate(ValueType&, const T&, unsigned hashCode);
+ template<typename T, typename HashTranslator> pair<iterator, bool> add(const T&, MappedPassInType);
+
+ void checkConsistency() const;
+
+ private:
+ pair<iterator, bool> inlineAdd(const KeyType&, MappedPassInReferenceType);
+
+ class HashMapKeysProxy : private HashMap {
+ public:
+ typedef typename HashMap::iterator::Keys iterator;
+ typedef typename HashMap::const_iterator::Keys const_iterator;
+
+ iterator begin()
+ {
+ return HashMap::begin().keys();
+ }
+
+ iterator end()
+ {
+ return HashMap::end().keys();
+ }
+
+ const_iterator begin() const
+ {
+ return HashMap::begin().keys();
+ }
+
+ const_iterator end() const
+ {
+ return HashMap::end().keys();
+ }
+
+ private:
+ friend class HashMap;
+
+ // These are intentionally not implemented.
+ HashMapKeysProxy();
+ HashMapKeysProxy(const HashMapKeysProxy&);
+ HashMapKeysProxy& operator=(const HashMapKeysProxy&);
+ ~HashMapKeysProxy();
+ };
+
+ class HashMapValuesProxy : private HashMap {
+ public:
+ typedef typename HashMap::iterator::Values iterator;
+ typedef typename HashMap::const_iterator::Values const_iterator;
+
+ iterator begin()
+ {
+ return HashMap::begin().values();
+ }
+
+ iterator end()
+ {
+ return HashMap::end().values();
+ }
+
+ const_iterator begin() const
+ {
+ return HashMap::begin().values();
+ }
+
+ const_iterator end() const
+ {
+ return HashMap::end().values();
+ }
+
+ private:
+ friend class HashMap;
+
+ // These are intentionally not implemented.
+ HashMapValuesProxy();
+ HashMapValuesProxy(const HashMapValuesProxy&);
+ HashMapValuesProxy& operator=(const HashMapValuesProxy&);
+ ~HashMapValuesProxy();
+ };
+
+ HashTableType m_impl;
+ };
+
+ template<typename PairType> struct PairFirstExtractor {
+ static const typename PairType::first_type& extract(const PairType& p) { return p.first; }
+ };
+
+ template<typename ValueTraits, typename HashFunctions>
+ struct HashMapTranslator {
+ template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
+ template<typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped)
+ {
+ location.first = key;
+ ValueTraits::SecondTraits::store(mapped, location.second);
+ }
+ };
+
+ template<typename ValueTraits, typename Translator>
+ struct HashMapTranslatorAdapter {
+ template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
+ template<typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped, unsigned hashCode)
+ {
+ Translator::translate(location.first, key, hashCode);
+ ValueTraits::SecondTraits::store(mapped, location.second);
+ }
+ };
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<T, U, V, W, X>::swap(HashMap& other)
+ {
+ m_impl.swap(other.m_impl);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline int HashMap<T, U, V, W, X>::size() const
+ {
+ return m_impl.size();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline int HashMap<T, U, V, W, X>::capacity() const
+ {
+ return m_impl.capacity();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool HashMap<T, U, V, W, X>::isEmpty() const
+ {
+ return m_impl.isEmpty();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::begin()
+ {
+ return m_impl.begin();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::end()
+ {
+ return m_impl.end();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::begin() const
+ {
+ return m_impl.begin();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::end() const
+ {
+ return m_impl.end();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::find(const KeyType& key)
+ {
+ return m_impl.find(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::find(const KeyType& key) const
+ {
+ return m_impl.find(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool HashMap<T, U, V, W, X>::contains(const KeyType& key) const
+ {
+ return m_impl.contains(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ template<typename TYPE, typename HashTranslator>
+ inline typename HashMap<T, U, V, W, X>::iterator
+ HashMap<T, U, V, W, X>::find(const TYPE& value)
+ {
+ return m_impl.template find<HashMapTranslatorAdapter<ValueTraits, HashTranslator> >(value);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ template<typename TYPE, typename HashTranslator>
+ inline typename HashMap<T, U, V, W, X>::const_iterator
+ HashMap<T, U, V, W, X>::find(const TYPE& value) const
+ {
+ return m_impl.template find<HashMapTranslatorAdapter<ValueTraits, HashTranslator> >(value);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ template<typename TYPE, typename HashTranslator>
+ inline bool
+ HashMap<T, U, V, W, X>::contains(const TYPE& value) const
+ {
+ return m_impl.template contains<HashMapTranslatorAdapter<ValueTraits, HashTranslator> >(value);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline pair<typename HashMap<T, U, V, W, X>::iterator, bool>
+ HashMap<T, U, V, W, X>::inlineAdd(const KeyType& key, MappedPassInReferenceType mapped)
+ {
+ return m_impl.template add<HashMapTranslator<ValueTraits, HashFunctions> >(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<T, U, V, W, X>::iterator, bool>
+ HashMap<T, U, V, W, X>::set(const KeyType& key, MappedPassInType mapped)
+ {
+ pair<iterator, bool> result = inlineAdd(key, mapped);
+ if (!result.second) {
+ // The inlineAdd call above found an existing hash table entry; we need to set the mapped value.
+ MappedTraits::store(mapped, result.first->second);
+ }
+ return result;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ template<typename TYPE, typename HashTranslator>
+ pair<typename HashMap<T, U, V, W, X>::iterator, bool>
+ HashMap<T, U, V, W, X>::add(const TYPE& key, MappedPassInType value)
+ {
+ return m_impl.template addPassingHashCode<HashMapTranslatorAdapter<ValueTraits, HashTranslator> >(key, value);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<T, U, V, W, X>::iterator, bool>
+ HashMap<T, U, V, W, X>::add(const KeyType& key, MappedPassInType mapped)
+ {
+ return inlineAdd(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<T, U, V, W, MappedTraits>::MappedPeekType
+ HashMap<T, U, V, W, MappedTraits>::get(const KeyType& key) const
+ {
+ ValueType* entry = const_cast<HashTableType&>(m_impl).lookup(key);
+ if (!entry)
+ return MappedTraits::peek(MappedTraits::emptyValue());
+ return MappedTraits::peek(entry->second);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<T, U, V, W, X>::remove(iterator it)
+ {
+ if (it.m_impl == m_impl.end())
+ return;
+ m_impl.internalCheckTableConsistency();
+ m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<T, U, V, W, X>::remove(const KeyType& key)
+ {
+ remove(find(key));
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<T, U, V, W, X>::clear()
+ {
+ m_impl.clear();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<T, U, V, W, MappedTraits>::MappedPassOutType
+ HashMap<T, U, V, W, MappedTraits>::take(const KeyType& key)
+ {
+ iterator it = find(key);
+ if (it == end())
+ return MappedTraits::passOut(MappedTraits::emptyValue());
+ MappedPassOutType result = MappedTraits::passOut(it->second);
+ remove(it);
+ return result;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<T, U, V, W, X>::checkConsistency() const
+ {
+ m_impl.checkTableConsistency();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ bool operator==(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
+ {
+ if (a.size() != b.size())
+ return false;
+
+ typedef typename HashMap<T, U, V, W, X>::const_iterator const_iterator;
+
+ const_iterator end = a.end();
+ const_iterator notFound = b.end();
+ for (const_iterator it = a.begin(); it != end; ++it) {
+ const_iterator bPos = b.find(it->first);
+ if (bPos == notFound || it->second != bPos->second)
+ return false;
+ }
+
+ return true;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool operator!=(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
+ {
+ return !(a == b);
+ }
+
+ template<typename HashTableType>
+ void deleteAllPairSeconds(HashTableType& collection)
+ {
+ typedef typename HashTableType::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete it->second;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void deleteAllValues(const HashMap<T, U, V, W, X>& collection)
+ {
+ deleteAllPairSeconds(collection);
+ }
+
+ template<typename HashTableType>
+ void deleteAllPairFirsts(HashTableType& collection)
+ {
+ typedef typename HashTableType::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete it->first;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void deleteAllKeys(const HashMap<T, U, V, W, X>& collection)
+ {
+ deleteAllPairFirsts(collection);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X, typename Y>
+ inline void copyKeysToVector(const HashMap<T, U, V, W, X>& collection, Y& vector)
+ {
+ typedef typename HashMap<T, U, V, W, X>::const_iterator::Keys iterator;
+
+ vector.resize(collection.size());
+
+ iterator it = collection.begin().keys();
+ iterator end = collection.end().keys();
+ for (unsigned i = 0; it != end; ++it, ++i)
+ vector[i] = *it;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X, typename Y>
+ inline void copyValuesToVector(const HashMap<T, U, V, W, X>& collection, Y& vector)
+ {
+ typedef typename HashMap<T, U, V, W, X>::const_iterator::Values iterator;
+
+ vector.resize(collection.size());
+
+ iterator it = collection.begin().values();
+ iterator end = collection.end().values();
+ for (unsigned i = 0; it != end; ++it, ++i)
+ vector[i] = *it;
+ }
+
+} // namespace WTF
+
+using WTF::HashMap;
+
+#include "RefPtrHashMap.h"
+
+#endif /* WTF_HashMap_h */
diff --git a/Source/JavaScriptCore/wtf/HashSet.h b/Source/JavaScriptCore/wtf/HashSet.h
new file mode 100644
index 000000000..7fce19348
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashSet.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 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_HashSet_h
+#define WTF_HashSet_h
+
+#include "FastAllocBase.h"
+#include "HashTable.h"
+
+namespace WTF {
+
+ struct IdentityExtractor;
+
+ template<typename Value, typename HashFunctions, typename Traits> class HashSet;
+ template<typename Value, typename HashFunctions, typename Traits>
+ void deleteAllValues(const HashSet<Value, HashFunctions, Traits>&);
+ template<typename Value, typename HashFunctions, typename Traits>
+ void fastDeleteAllValues(const HashSet<Value, HashFunctions, Traits>&);
+
+ template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash,
+ typename TraitsArg = HashTraits<ValueArg> > class HashSet {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef HashArg HashFunctions;
+ typedef TraitsArg ValueTraits;
+
+ public:
+ typedef typename ValueTraits::TraitType ValueType;
+
+ private:
+ typedef HashTable<ValueType, ValueType, IdentityExtractor,
+ HashFunctions, ValueTraits, ValueTraits> HashTableType;
+
+ public:
+ typedef HashTableConstIteratorAdapter<HashTableType, ValueType> iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
+
+ void swap(HashSet&);
+
+ int size() const;
+ int capacity() const;
+ bool isEmpty() const;
+
+ iterator begin() const;
+ iterator end() const;
+
+ iterator find(const ValueType&) const;
+ bool contains(const ValueType&) const;
+
+ // An alternate version of find() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion. HashTranslator
+ // must have the following function members:
+ // static unsigned hash(const T&);
+ // static bool equal(const ValueType&, const T&);
+ // FIXME: We should reverse the order of the template arguments so that callers
+ // can just pass the translator and let the compiler deduce T.
+ 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,
+ // and a bool that is true if an new entry was added.
+ pair<iterator, bool> add(const ValueType&);
+
+ // An alternate version of add() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion if the object is already
+ // in the table. HashTranslator must have the following function members:
+ // static unsigned hash(const T&);
+ // static bool equal(const ValueType&, const T&);
+ // static translate(ValueType&, const T&, unsigned hashCode);
+ // FIXME: We should reverse the order of the template arguments so that callers
+ // can just pass the translator and let the compiler deduce T.
+ template<typename T, typename HashTranslator> pair<iterator, bool> add(const T&);
+
+ void remove(const ValueType&);
+ void remove(iterator);
+ void clear();
+
+ private:
+ friend void deleteAllValues<>(const HashSet&);
+ friend void fastDeleteAllValues<>(const HashSet&);
+
+ HashTableType m_impl;
+ };
+
+ struct IdentityExtractor {
+ template<typename T> static const T& extract(const T& t) { return t; }
+ };
+
+ template<typename Translator>
+ struct HashSetTranslatorAdapter {
+ template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
+ template<typename T, typename U> static void translate(T& location, const U& key, const U&, unsigned hashCode)
+ {
+ Translator::translate(location, key, hashCode);
+ }
+ };
+
+ template<typename T, typename U, typename V>
+ inline void HashSet<T, U, V>::swap(HashSet& other)
+ {
+ m_impl.swap(other.m_impl);
+ }
+
+ template<typename T, typename U, typename V>
+ inline int HashSet<T, U, V>::size() const
+ {
+ return m_impl.size();
+ }
+
+ template<typename T, typename U, typename V>
+ inline int HashSet<T, U, V>::capacity() const
+ {
+ return m_impl.capacity();
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool HashSet<T, U, V>::isEmpty() const
+ {
+ return m_impl.isEmpty();
+ }
+
+ template<typename T, typename U, typename V>
+ 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() 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) const
+ {
+ return m_impl.find(value);
+ }
+
+ template<typename T, typename U, typename V>
+ inline bool HashSet<T, U, V>::contains(const ValueType& value) const
+ {
+ return m_impl.contains(value);
+ }
+
+ 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) const
+ {
+ return m_impl.template find<HashSetTranslatorAdapter<HashTranslator> >(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ template<typename T, typename HashTranslator>
+ inline bool HashSet<Value, HashFunctions, Traits>::contains(const T& value) const
+ {
+ return m_impl.template contains<HashSetTranslatorAdapter<HashTranslator> >(value);
+ }
+
+ template<typename T, typename U, typename V>
+ inline pair<typename HashSet<T, U, V>::iterator, bool> HashSet<T, U, V>::add(const ValueType& value)
+ {
+ return m_impl.add(value);
+ }
+
+ template<typename Value, typename HashFunctions, typename Traits>
+ template<typename T, typename HashTranslator>
+ inline pair<typename HashSet<Value, HashFunctions, Traits>::iterator, bool>
+ HashSet<Value, HashFunctions, Traits>::add(const T& value)
+ {
+ return m_impl.template addPassingHashCode<HashSetTranslatorAdapter<HashTranslator> >(value, value);
+ }
+
+ template<typename T, typename U, typename V>
+ inline void HashSet<T, U, V>::remove(iterator it)
+ {
+ if (it.m_impl == m_impl.end())
+ return;
+ m_impl.internalCheckTableConsistency();
+ m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
+ }
+
+ template<typename T, typename U, typename V>
+ inline void HashSet<T, U, V>::remove(const ValueType& value)
+ {
+ remove(find(value));
+ }
+
+ template<typename T, typename U, typename V>
+ inline void HashSet<T, U, V>::clear()
+ {
+ m_impl.clear();
+ }
+
+ template<typename ValueType, typename HashTableType>
+ void deleteAllValues(HashTableType& collection)
+ {
+ typedef typename HashTableType::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete *it;
+ }
+
+ template<typename T, typename U, typename V>
+ inline void deleteAllValues(const HashSet<T, U, V>& collection)
+ {
+ deleteAllValues<typename HashSet<T, U, V>::ValueType>(collection.m_impl);
+ }
+
+ template<typename ValueType, typename HashTableType>
+ void fastDeleteAllValues(HashTableType& collection)
+ {
+ typedef typename HashTableType::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ fastDelete(*it);
+ }
+
+ template<typename T, typename U, typename V>
+ inline void fastDeleteAllValues(const HashSet<T, U, V>& collection)
+ {
+ fastDeleteAllValues<typename HashSet<T, U, V>::ValueType>(collection.m_impl);
+ }
+
+ template<typename T, typename U, typename V, typename W>
+ inline void copyToVector(const HashSet<T, U, V>& collection, W& vector)
+ {
+ typedef typename HashSet<T, U, V>::const_iterator iterator;
+
+ vector.resize(collection.size());
+
+ iterator it = collection.begin();
+ iterator end = collection.end();
+ for (unsigned i = 0; it != end; ++it, ++i)
+ vector[i] = *it;
+ }
+
+} // namespace WTF
+
+using WTF::HashSet;
+
+#endif /* WTF_HashSet_h */
diff --git a/Source/JavaScriptCore/wtf/HashTable.cpp b/Source/JavaScriptCore/wtf/HashTable.cpp
new file mode 100644
index 000000000..71d3f86ce
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashTable.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2005 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 "HashTable.h"
+
+namespace WTF {
+
+#if DUMP_HASHTABLE_STATS
+
+int HashTableStats::numAccesses;
+int HashTableStats::numCollisions;
+int HashTableStats::collisionGraph[4096];
+int HashTableStats::maxCollisions;
+int HashTableStats::numRehashes;
+int HashTableStats::numRemoves;
+int HashTableStats::numReinserts;
+
+static HashTableStats logger;
+
+static Mutex& hashTableStatsMutex()
+{
+ AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
+ return mutex;
+}
+
+HashTableStats::~HashTableStats()
+{
+ // Don't lock hashTableStatsMutex here because it can cause deadlocks at shutdown
+ // if any thread was killed while holding the mutex.
+ printf("\nWTF::HashTable statistics\n\n");
+ printf("%d accesses\n", numAccesses);
+ printf("%d total collisions, average %.2f probes per access\n", numCollisions, 1.0 * (numAccesses + numCollisions) / numAccesses);
+ printf("longest collision chain: %d\n", maxCollisions);
+ for (int i = 1; i <= maxCollisions; i++) {
+ printf(" %d lookups with exactly %d collisions (%.2f%% , %.2f%% with this many or more)\n", collisionGraph[i], i, 100.0 * (collisionGraph[i] - collisionGraph[i+1]) / numAccesses, 100.0 * collisionGraph[i] / numAccesses);
+ }
+ printf("%d rehashes\n", numRehashes);
+ printf("%d reinserts\n", numReinserts);
+}
+
+void HashTableStats::recordCollisionAtCount(int count)
+{
+ MutexLocker lock(hashTableStatsMutex());
+ if (count > maxCollisions)
+ maxCollisions = count;
+ numCollisions++;
+ collisionGraph[count]++;
+}
+
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/HashTable.h b/Source/JavaScriptCore/wtf/HashTable.h
new file mode 100644
index 000000000..44f914330
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashTable.h
@@ -0,0 +1,1244 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 David Levin <levin@chromium.org>
+ *
+ * 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_HashTable_h
+#define WTF_HashTable_h
+
+#include "Alignment.h"
+#include "Assertions.h"
+#include "FastMalloc.h"
+#include "HashTraits.h"
+#include "StdLibExtras.h"
+#include "Threading.h"
+#include "ValueCheck.h"
+
+namespace WTF {
+
+#define DUMP_HASHTABLE_STATS 0
+
+// Enables internal WTF consistency checks that are invoked automatically. Non-WTF callers can call checkTableConsistency() even if internal checks are disabled.
+#define CHECK_HASHTABLE_CONSISTENCY 0
+
+#ifdef NDEBUG
+#define CHECK_HASHTABLE_ITERATORS 0
+#define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 0
+#else
+#define CHECK_HASHTABLE_ITERATORS 1
+#define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 1
+#endif
+
+#if DUMP_HASHTABLE_STATS
+
+ struct HashTableStats {
+ ~HashTableStats();
+ // All of the variables are accessed in ~HashTableStats when the static struct is destroyed.
+
+ // The following variables are all atomically incremented when modified.
+ static int numAccesses;
+ static int numRehashes;
+ static int numRemoves;
+ static int numReinserts;
+
+ // The following variables are only modified in the recordCollisionAtCount method within a mutex.
+ static int maxCollisions;
+ static int numCollisions;
+ static int collisionGraph[4096];
+
+ static void recordCollisionAtCount(int count);
+ };
+
+#endif
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTable;
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTableIterator;
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTableConstIterator;
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*,
+ HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*);
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*);
+
+#if !CHECK_HASHTABLE_ITERATORS
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*,
+ HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { }
+
+#endif
+
+ typedef enum { HashItemKnownGood } HashItemKnownGoodTag;
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTableConstIterator {
+ private:
+ typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
+ typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
+ typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
+ typedef Value ValueType;
+ typedef const ValueType& ReferenceType;
+ typedef const ValueType* PointerType;
+
+ friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
+ friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
+
+ void skipEmptyBuckets()
+ {
+ while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBucket(*m_position))
+ ++m_position;
+ }
+
+ HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition)
+ : m_position(position), m_endPosition(endPosition)
+ {
+ addIterator(table, this);
+ skipEmptyBuckets();
+ }
+
+ HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition, HashItemKnownGoodTag)
+ : m_position(position), m_endPosition(endPosition)
+ {
+ addIterator(table, this);
+ }
+
+ public:
+ HashTableConstIterator()
+ {
+ addIterator(static_cast<const HashTableType*>(0), this);
+ }
+
+ // default copy, assignment and destructor are OK if CHECK_HASHTABLE_ITERATORS is 0
+
+#if CHECK_HASHTABLE_ITERATORS
+ ~HashTableConstIterator()
+ {
+ removeIterator(this);
+ }
+
+ HashTableConstIterator(const const_iterator& other)
+ : m_position(other.m_position), m_endPosition(other.m_endPosition)
+ {
+ addIterator(other.m_table, this);
+ }
+
+ const_iterator& operator=(const const_iterator& other)
+ {
+ m_position = other.m_position;
+ m_endPosition = other.m_endPosition;
+
+ removeIterator(this);
+ addIterator(other.m_table, this);
+
+ return *this;
+ }
+#endif
+
+ PointerType get() const
+ {
+ checkValidity();
+ return m_position;
+ }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ const_iterator& operator++()
+ {
+ checkValidity();
+ ASSERT(m_position != m_endPosition);
+ ++m_position;
+ skipEmptyBuckets();
+ return *this;
+ }
+
+ // postfix ++ intentionally omitted
+
+ // Comparison.
+ bool operator==(const const_iterator& other) const
+ {
+ checkValidity(other);
+ return m_position == other.m_position;
+ }
+ bool operator!=(const const_iterator& other) const
+ {
+ checkValidity(other);
+ return m_position != other.m_position;
+ }
+ bool operator==(const iterator& other) const
+ {
+ return *this == static_cast<const_iterator>(other);
+ }
+ bool operator!=(const iterator& other) const
+ {
+ return *this != static_cast<const_iterator>(other);
+ }
+
+ private:
+ void checkValidity() const
+ {
+#if CHECK_HASHTABLE_ITERATORS
+ ASSERT(m_table);
+#endif
+ }
+
+
+#if CHECK_HASHTABLE_ITERATORS
+ void checkValidity(const const_iterator& other) const
+ {
+ ASSERT(m_table);
+ ASSERT_UNUSED(other, other.m_table);
+ ASSERT(m_table == other.m_table);
+ }
+#else
+ void checkValidity(const const_iterator&) const { }
+#endif
+
+ PointerType m_position;
+ PointerType m_endPosition;
+
+#if CHECK_HASHTABLE_ITERATORS
+ public:
+ // Any modifications of the m_next or m_previous of an iterator that is in a linked list of a HashTable::m_iterator,
+ // should be guarded with m_table->m_mutex.
+ mutable const HashTableType* m_table;
+ mutable const_iterator* m_next;
+ mutable const_iterator* m_previous;
+#endif
+ };
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTableIterator {
+ private:
+ typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
+ typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
+ typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
+ typedef Value ValueType;
+ typedef ValueType& ReferenceType;
+ typedef ValueType* PointerType;
+
+ friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
+
+ HashTableIterator(HashTableType* table, PointerType pos, PointerType end) : m_iterator(table, pos, end) { }
+ HashTableIterator(HashTableType* table, PointerType pos, PointerType end, HashItemKnownGoodTag tag) : m_iterator(table, pos, end, tag) { }
+
+ public:
+ HashTableIterator() { }
+
+ // default copy, assignment and destructor are OK
+
+ PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ iterator& operator++() { ++m_iterator; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ // Comparison.
+ bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
+ bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
+ bool operator==(const const_iterator& other) const { return m_iterator == other; }
+ bool operator!=(const const_iterator& other) const { return m_iterator != other; }
+
+ operator const_iterator() const { return m_iterator; }
+
+ private:
+ const_iterator m_iterator;
+ };
+
+ using std::swap;
+
+ // Work around MSVC's standard library, whose swap for pairs does not swap by component.
+ template<typename T> inline void hashTableSwap(T& a, T& b)
+ {
+ swap(a, b);
+ }
+
+ // Swap pairs by component, in case of pair members that specialize swap.
+ template<typename T, typename U> inline void hashTableSwap(pair<T, U>& a, pair<T, U>& b)
+ {
+ swap(a.first, b.first);
+ swap(a.second, b.second);
+ }
+
+ template<typename T, bool useSwap> struct Mover;
+ template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { hashTableSwap(from, to); } };
+ template<typename T> struct Mover<T, false> { static void move(T& from, T& to) { to = from; } };
+
+ template<typename HashFunctions> class IdentityHashTranslator {
+ public:
+ template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
+ template<typename T> static bool equal(const T& a, const T& b) { return HashFunctions::equal(a, b); }
+ template<typename T, typename U> static void translate(T& location, const U&, const T& value) { location = value; }
+ };
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ class HashTable {
+ public:
+ typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
+ typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
+ typedef Traits ValueTraits;
+ typedef Key KeyType;
+ typedef Value ValueType;
+ typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType;
+
+ HashTable();
+ ~HashTable()
+ {
+ invalidateIterators();
+ deallocateTable(m_table, m_tableSize);
+#if CHECK_HASHTABLE_USE_AFTER_DESTRUCTION
+ m_table = (ValueType*)(uintptr_t)0xbbadbeef;
+#endif
+ }
+
+ HashTable(const HashTable&);
+ void swap(HashTable&);
+ HashTable& operator=(const HashTable&);
+
+ iterator begin() { return makeIterator(m_table); }
+ iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); }
+ const_iterator begin() const { return makeConstIterator(m_table); }
+ const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_tableSize); }
+
+ int size() const { return m_keyCount; }
+ int capacity() const { return m_tableSize; }
+ bool isEmpty() const { return !m_keyCount; }
+
+ pair<iterator, bool> add(const ValueType& value) { return add<IdentityTranslatorType>(Extractor::extract(value), value); }
+
+ // A special version of add() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion if the object is already
+ // in the table.
+ template<typename HashTranslator, typename T, typename Extra> pair<iterator, bool> add(const T& key, const Extra&);
+ template<typename HashTranslator, typename T, typename Extra> pair<iterator, bool> addPassingHashCode(const T& key, const Extra&);
+
+ iterator find(const KeyType& key) { return find<IdentityTranslatorType>(key); }
+ const_iterator find(const KeyType& key) const { return find<IdentityTranslatorType>(key); }
+ bool contains(const KeyType& key) const { return contains<IdentityTranslatorType>(key); }
+
+ template<typename HashTranslator, typename T> iterator find(const T&);
+ template<typename HashTranslator, typename T> const_iterator find(const T&) const;
+ template<typename HashTranslator, typename T> bool contains(const T&) const;
+
+ 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(); }
+ static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); }
+ static bool isEmptyOrDeletedBucket(const ValueType& value) { return isEmptyBucket(value) || isDeletedBucket(value); }
+
+ ValueType* lookup(const Key& key) { return lookup<IdentityTranslatorType>(key); }
+ template<typename HashTranslator, typename T> ValueType* lookup(const T&);
+
+#if !ASSERT_DISABLED
+ void checkTableConsistency() const;
+#else
+ static void checkTableConsistency() { }
+#endif
+#if CHECK_HASHTABLE_CONSISTENCY
+ void internalCheckTableConsistency() const { checkTableConsistency(); }
+ void internalCheckTableConsistencyExceptSize() const { checkTableConsistencyExceptSize(); }
+#else
+ static void internalCheckTableConsistencyExceptSize() { }
+ static void internalCheckTableConsistency() { }
+#endif
+
+ private:
+ static ValueType* allocateTable(int size);
+ static void deallocateTable(ValueType* table, int size);
+
+ typedef pair<ValueType*, bool> LookupType;
+ typedef pair<LookupType, unsigned> FullLookupType;
+
+ LookupType lookupForWriting(const Key& key) { return lookupForWriting<IdentityTranslatorType>(key); };
+ template<typename HashTranslator, typename T> FullLookupType fullLookupForWriting(const T&);
+ template<typename HashTranslator, typename T> LookupType lookupForWriting(const T&);
+
+ template<typename HashTranslator, typename T> void checkKey(const T&);
+
+ void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType*);
+ void removeAndInvalidate(ValueType*);
+ void remove(ValueType*);
+
+ bool shouldExpand() const { return (m_keyCount + m_deletedCount) * m_maxLoad >= m_tableSize; }
+ bool mustRehashInPlace() const { return m_keyCount * m_minLoad < m_tableSize * 2; }
+ bool shouldShrink() const { return m_keyCount * m_minLoad < m_tableSize && m_tableSize > KeyTraits::minimumTableSize; }
+ void expand();
+ void shrink() { rehash(m_tableSize / 2); }
+
+ void rehash(int newTableSize);
+ void reinsert(ValueType&);
+
+ static void initializeBucket(ValueType& bucket);
+ static void deleteBucket(ValueType& bucket) { bucket.~ValueType(); Traits::constructDeletedValue(bucket); }
+
+ FullLookupType makeLookupResult(ValueType* position, bool found, unsigned hash)
+ { return FullLookupType(LookupType(position, found), hash); }
+
+ iterator makeIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize); }
+ const_iterator makeConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize); }
+ iterator makeKnownGoodIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); }
+ const_iterator makeKnownGoodConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); }
+
+#if !ASSERT_DISABLED
+ void checkTableConsistencyExceptSize() const;
+#else
+ static void checkTableConsistencyExceptSize() { }
+#endif
+
+#if CHECK_HASHTABLE_ITERATORS
+ void invalidateIterators();
+#else
+ static void invalidateIterators() { }
+#endif
+
+ static const int m_maxLoad = 2;
+ static const int m_minLoad = 6;
+
+ ValueType* m_table;
+ int m_tableSize;
+ int m_tableSizeMask;
+ int m_keyCount;
+ int m_deletedCount;
+
+#if CHECK_HASHTABLE_ITERATORS
+ public:
+ // All access to m_iterators should be guarded with m_mutex.
+ mutable const_iterator* m_iterators;
+ mutable Mutex m_mutex;
+#endif
+ };
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable()
+ : m_table(0)
+ , m_tableSize(0)
+ , m_tableSizeMask(0)
+ , m_keyCount(0)
+ , m_deletedCount(0)
+#if CHECK_HASHTABLE_ITERATORS
+ , m_iterators(0)
+#endif
+ {
+ }
+
+ inline unsigned doubleHash(unsigned key)
+ {
+ key = ~key + (key >> 23);
+ key ^= (key << 12);
+ key ^= (key >> 7);
+ key ^= (key << 2);
+ key ^= (key >> 20);
+ return key;
+ }
+
+#if ASSERT_DISABLED
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T&)
+ {
+ }
+
+#else
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T& key)
+ {
+ if (!HashFunctions::safeToCompareToEmptyOrDeleted)
+ return;
+ ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key));
+ AlignedBuffer<sizeof(ValueType), WTF_ALIGN_OF(ValueType)> deletedValueBuffer;
+ ValueType& deletedValue = *reinterpret_cast_ptr<ValueType*>(deletedValueBuffer.buffer);
+ Traits::constructDeletedValue(deletedValue);
+ ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue), key));
+ }
+
+#endif
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T>
+ inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key)
+ {
+ checkKey<HashTranslator>(key);
+
+ int k = 0;
+ int sizeMask = m_tableSizeMask;
+ ValueType* table = m_table;
+ unsigned h = HashTranslator::hash(key);
+ int i = h & sizeMask;
+
+ if (!table)
+ return 0;
+
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numAccesses);
+ int probeCount = 0;
+#endif
+
+ while (1) {
+ ValueType* entry = table + i;
+
+ // we count on the compiler to optimize out this branch
+ if (HashFunctions::safeToCompareToEmptyOrDeleted) {
+ if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return entry;
+
+ if (isEmptyBucket(*entry))
+ return 0;
+ } else {
+ if (isEmptyBucket(*entry))
+ return 0;
+
+ if (!isDeletedBucket(*entry) && HashTranslator::equal(Extractor::extract(*entry), key))
+ return entry;
+ }
+#if DUMP_HASHTABLE_STATS
+ ++probeCount;
+ HashTableStats::recordCollisionAtCount(probeCount);
+#endif
+ if (k == 0)
+ k = 1 | doubleHash(h);
+ i = (i + k) & sizeMask;
+ }
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T>
+ inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookupForWriting(const T& key)
+ {
+ ASSERT(m_table);
+ checkKey<HashTranslator>(key);
+
+ int k = 0;
+ ValueType* table = m_table;
+ int sizeMask = m_tableSizeMask;
+ unsigned h = HashTranslator::hash(key);
+ int i = h & sizeMask;
+
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numAccesses);
+ int probeCount = 0;
+#endif
+
+ ValueType* deletedEntry = 0;
+
+ while (1) {
+ ValueType* entry = table + i;
+
+ // we count on the compiler to optimize out this branch
+ if (HashFunctions::safeToCompareToEmptyOrDeleted) {
+ if (isEmptyBucket(*entry))
+ return LookupType(deletedEntry ? deletedEntry : entry, false);
+
+ if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return LookupType(entry, true);
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ } else {
+ if (isEmptyBucket(*entry))
+ return LookupType(deletedEntry ? deletedEntry : entry, false);
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ else if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return LookupType(entry, true);
+ }
+#if DUMP_HASHTABLE_STATS
+ ++probeCount;
+ HashTableStats::recordCollisionAtCount(probeCount);
+#endif
+ if (k == 0)
+ k = 1 | doubleHash(h);
+ i = (i + k) & sizeMask;
+ }
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T>
+ inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::fullLookupForWriting(const T& key)
+ {
+ ASSERT(m_table);
+ checkKey<HashTranslator>(key);
+
+ int k = 0;
+ ValueType* table = m_table;
+ int sizeMask = m_tableSizeMask;
+ unsigned h = HashTranslator::hash(key);
+ int i = h & sizeMask;
+
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numAccesses);
+ int probeCount = 0;
+#endif
+
+ ValueType* deletedEntry = 0;
+
+ while (1) {
+ ValueType* entry = table + i;
+
+ // we count on the compiler to optimize out this branch
+ if (HashFunctions::safeToCompareToEmptyOrDeleted) {
+ if (isEmptyBucket(*entry))
+ return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h);
+
+ if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return makeLookupResult(entry, true, h);
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ } else {
+ if (isEmptyBucket(*entry))
+ return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h);
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ else if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return makeLookupResult(entry, true, h);
+ }
+#if DUMP_HASHTABLE_STATS
+ ++probeCount;
+ HashTableStats::recordCollisionAtCount(probeCount);
+#endif
+ if (k == 0)
+ k = 1 | doubleHash(h);
+ i = (i + k) & sizeMask;
+ }
+ }
+
+ template<bool emptyValueIsZero> struct HashTableBucketInitializer;
+
+ template<> struct HashTableBucketInitializer<false> {
+ template<typename Traits, typename Value> static void initialize(Value& bucket)
+ {
+ new (NotNull, &bucket) Value(Traits::emptyValue());
+ }
+ };
+
+ template<> struct HashTableBucketInitializer<true> {
+ template<typename Traits, typename Value> static void initialize(Value& bucket)
+ {
+ // This initializes the bucket without copying the empty value.
+ // That makes it possible to use this with types that don't support copying.
+ // The memset to 0 looks like a slow operation but is optimized by the compilers.
+ memset(&bucket, 0, sizeof(bucket));
+ }
+ };
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::initializeBucket(ValueType& bucket)
+ {
+ HashTableBucketInitializer<Traits::emptyValueIsZero>::template initialize<Traits>(bucket);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T, typename Extra>
+ inline pair<typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator, bool> HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::add(const T& key, const Extra& extra)
+ {
+ checkKey<HashTranslator>(key);
+
+ invalidateIterators();
+
+ if (!m_table)
+ expand();
+
+ internalCheckTableConsistency();
+
+ ASSERT(m_table);
+
+ int k = 0;
+ ValueType* table = m_table;
+ int sizeMask = m_tableSizeMask;
+ unsigned h = HashTranslator::hash(key);
+ int i = h & sizeMask;
+
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numAccesses);
+ int probeCount = 0;
+#endif
+
+ ValueType* deletedEntry = 0;
+ ValueType* entry;
+ while (1) {
+ entry = table + i;
+
+ // we count on the compiler to optimize out this branch
+ if (HashFunctions::safeToCompareToEmptyOrDeleted) {
+ if (isEmptyBucket(*entry))
+ break;
+
+ if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return std::make_pair(makeKnownGoodIterator(entry), false);
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ } else {
+ if (isEmptyBucket(*entry))
+ break;
+
+ if (isDeletedBucket(*entry))
+ deletedEntry = entry;
+ else if (HashTranslator::equal(Extractor::extract(*entry), key))
+ return std::make_pair(makeKnownGoodIterator(entry), false);
+ }
+#if DUMP_HASHTABLE_STATS
+ ++probeCount;
+ HashTableStats::recordCollisionAtCount(probeCount);
+#endif
+ if (k == 0)
+ k = 1 | doubleHash(h);
+ i = (i + k) & sizeMask;
+ }
+
+ if (deletedEntry) {
+ initializeBucket(*deletedEntry);
+ entry = deletedEntry;
+ --m_deletedCount;
+ }
+
+ HashTranslator::translate(*entry, key, extra);
+
+ ++m_keyCount;
+
+ if (shouldExpand()) {
+ // FIXME: This makes an extra copy on expand. Probably not that bad since
+ // expand is rare, but would be better to have a version of expand that can
+ // follow a pivot entry and return the new position.
+ KeyType enteredKey = Extractor::extract(*entry);
+ expand();
+ pair<iterator, bool> p = std::make_pair(find(enteredKey), true);
+ ASSERT(p.first != end());
+ return p;
+ }
+
+ internalCheckTableConsistency();
+
+ return std::make_pair(makeKnownGoodIterator(entry), true);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template<typename HashTranslator, typename T, typename Extra>
+ inline pair<typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator, bool> HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::addPassingHashCode(const T& key, const Extra& extra)
+ {
+ checkKey<HashTranslator>(key);
+
+ invalidateIterators();
+
+ if (!m_table)
+ expand();
+
+ internalCheckTableConsistency();
+
+ FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key);
+
+ ValueType* entry = lookupResult.first.first;
+ bool found = lookupResult.first.second;
+ unsigned h = lookupResult.second;
+
+ if (found)
+ return std::make_pair(makeKnownGoodIterator(entry), false);
+
+ if (isDeletedBucket(*entry)) {
+ initializeBucket(*entry);
+ --m_deletedCount;
+ }
+
+ HashTranslator::translate(*entry, key, extra, h);
+ ++m_keyCount;
+ if (shouldExpand()) {
+ // FIXME: This makes an extra copy on expand. Probably not that bad since
+ // expand is rare, but would be better to have a version of expand that can
+ // follow a pivot entry and return the new position.
+ KeyType enteredKey = Extractor::extract(*entry);
+ expand();
+ pair<iterator, bool> p = std::make_pair(find(enteredKey), true);
+ ASSERT(p.first != end());
+ return p;
+ }
+
+ internalCheckTableConsistency();
+
+ return std::make_pair(makeKnownGoodIterator(entry), true);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::reinsert(ValueType& entry)
+ {
+ ASSERT(m_table);
+ ASSERT(!lookupForWriting(Extractor::extract(entry)).second);
+ ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).first)));
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numReinserts);
+#endif
+
+ Mover<ValueType, Traits::needsDestruction>::move(entry, *lookupForWriting(Extractor::extract(entry)).first);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template <typename HashTranslator, typename T>
+ typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key)
+ {
+ if (!m_table)
+ return end();
+
+ ValueType* entry = lookup<HashTranslator>(key);
+ if (!entry)
+ return end();
+
+ return makeKnownGoodIterator(entry);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template <typename HashTranslator, typename T>
+ typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::const_iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key) const
+ {
+ if (!m_table)
+ return end();
+
+ ValueType* entry = const_cast<HashTable*>(this)->lookup<HashTranslator>(key);
+ if (!entry)
+ return end();
+
+ return makeKnownGoodConstIterator(entry);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ template <typename HashTranslator, typename T>
+ bool HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::contains(const T& key) const
+ {
+ if (!m_table)
+ return false;
+
+ return const_cast<HashTable*>(this)->lookup<HashTranslator>(key);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck(ValueType* pos)
+ {
+ invalidateIterators();
+ remove(pos);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeAndInvalidate(ValueType* pos)
+ {
+ invalidateIterators();
+ internalCheckTableConsistency();
+ remove(pos);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(ValueType* pos)
+ {
+#if DUMP_HASHTABLE_STATS
+ atomicIncrement(&HashTableStats::numRemoves);
+#endif
+
+ deleteBucket(*pos);
+ ++m_deletedCount;
+ --m_keyCount;
+
+ if (shouldShrink())
+ shrink();
+
+ internalCheckTableConsistency();
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(iterator it)
+ {
+ if (it == end())
+ return;
+
+ removeAndInvalidate(const_cast<ValueType*>(it.m_iterator.m_position));
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeWithoutEntryConsistencyCheck(iterator it)
+ {
+ if (it == end())
+ return;
+
+ removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_iterator.m_position));
+ }
+
+ 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));
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::allocateTable(int size)
+ {
+ // would use a template member function with explicit specializations here, but
+ // gcc doesn't appear to support that
+ if (Traits::emptyValueIsZero)
+ return static_cast<ValueType*>(fastZeroedMalloc(size * sizeof(ValueType)));
+ ValueType* result = static_cast<ValueType*>(fastMalloc(size * sizeof(ValueType)));
+ for (int i = 0; i < size; i++)
+ initializeBucket(result[i]);
+ return result;
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::deallocateTable(ValueType* table, int size)
+ {
+ if (Traits::needsDestruction) {
+ for (int i = 0; i < size; ++i) {
+ if (!isDeletedBucket(table[i]))
+ table[i].~ValueType();
+ }
+ }
+ fastFree(table);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::expand()
+ {
+ int newSize;
+ if (m_tableSize == 0)
+ newSize = KeyTraits::minimumTableSize;
+ else if (mustRehashInPlace())
+ newSize = m_tableSize;
+ else
+ newSize = m_tableSize * 2;
+
+ rehash(newSize);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::rehash(int newTableSize)
+ {
+ internalCheckTableConsistencyExceptSize();
+
+ int oldTableSize = m_tableSize;
+ ValueType* oldTable = m_table;
+
+#if DUMP_HASHTABLE_STATS
+ if (oldTableSize != 0)
+ atomicIncrement(&HashTableStats::numRehashes);
+#endif
+
+ m_tableSize = newTableSize;
+ m_tableSizeMask = newTableSize - 1;
+ m_table = allocateTable(newTableSize);
+
+ for (int i = 0; i != oldTableSize; ++i)
+ if (!isEmptyOrDeletedBucket(oldTable[i]))
+ reinsert(oldTable[i]);
+
+ m_deletedCount = 0;
+
+ deallocateTable(oldTable, oldTableSize);
+
+ internalCheckTableConsistency();
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::clear()
+ {
+ invalidateIterators();
+ deallocateTable(m_table, m_tableSize);
+ m_table = 0;
+ m_tableSize = 0;
+ m_tableSizeMask = 0;
+ m_keyCount = 0;
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable(const HashTable& other)
+ : m_table(0)
+ , m_tableSize(0)
+ , m_tableSizeMask(0)
+ , m_keyCount(0)
+ , m_deletedCount(0)
+#if CHECK_HASHTABLE_ITERATORS
+ , m_iterators(0)
+#endif
+ {
+ // Copy the hash table the dumb way, by adding each element to the new table.
+ // It might be more efficient to copy the table slots, but it's not clear that efficiency is needed.
+ const_iterator end = other.end();
+ for (const_iterator it = other.begin(); it != end; ++it)
+ add(*it);
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::swap(HashTable& other)
+ {
+ invalidateIterators();
+ other.invalidateIterators();
+
+ ValueType* tmp_table = m_table;
+ m_table = other.m_table;
+ other.m_table = tmp_table;
+
+ int tmp_tableSize = m_tableSize;
+ m_tableSize = other.m_tableSize;
+ other.m_tableSize = tmp_tableSize;
+
+ int tmp_tableSizeMask = m_tableSizeMask;
+ m_tableSizeMask = other.m_tableSizeMask;
+ other.m_tableSizeMask = tmp_tableSizeMask;
+
+ int tmp_keyCount = m_keyCount;
+ m_keyCount = other.m_keyCount;
+ other.m_keyCount = tmp_keyCount;
+
+ int tmp_deletedCount = m_deletedCount;
+ m_deletedCount = other.m_deletedCount;
+ other.m_deletedCount = tmp_deletedCount;
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>& HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::operator=(const HashTable& other)
+ {
+ HashTable tmp(other);
+ swap(tmp);
+ return *this;
+ }
+
+#if !ASSERT_DISABLED
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkTableConsistency() const
+ {
+ checkTableConsistencyExceptSize();
+ ASSERT(!m_table || !shouldExpand());
+ ASSERT(!shouldShrink());
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkTableConsistencyExceptSize() const
+ {
+ if (!m_table)
+ return;
+
+ int count = 0;
+ int deletedCount = 0;
+ for (int j = 0; j < m_tableSize; ++j) {
+ ValueType* entry = m_table + j;
+ if (isEmptyBucket(*entry))
+ continue;
+
+ if (isDeletedBucket(*entry)) {
+ ++deletedCount;
+ continue;
+ }
+
+ const_iterator it = find(Extractor::extract(*entry));
+ ASSERT(entry == it.m_position);
+ ++count;
+
+ ValueCheck<Key>::checkConsistency(it->first);
+ }
+
+ ASSERT(count == m_keyCount);
+ ASSERT(deletedCount == m_deletedCount);
+ ASSERT(m_tableSize >= KeyTraits::minimumTableSize);
+ ASSERT(m_tableSizeMask);
+ ASSERT(m_tableSize == m_tableSizeMask + 1);
+ }
+
+#endif // ASSERT_DISABLED
+
+#if CHECK_HASHTABLE_ITERATORS
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::invalidateIterators()
+ {
+ MutexLocker lock(m_mutex);
+ const_iterator* next;
+ for (const_iterator* p = m_iterators; p; p = next) {
+ next = p->m_next;
+ p->m_table = 0;
+ p->m_next = 0;
+ p->m_previous = 0;
+ }
+ m_iterators = 0;
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* table,
+ HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* it)
+ {
+ it->m_table = table;
+ it->m_previous = 0;
+
+ // Insert iterator at head of doubly-linked list of iterators.
+ if (!table) {
+ it->m_next = 0;
+ } else {
+ MutexLocker lock(table->m_mutex);
+ ASSERT(table->m_iterators != it);
+ it->m_next = table->m_iterators;
+ table->m_iterators = it;
+ if (it->m_next) {
+ ASSERT(!it->m_next->m_previous);
+ it->m_next->m_previous = it;
+ }
+ }
+ }
+
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* it)
+ {
+ typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
+ typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
+
+ // Delete iterator from doubly-linked list of iterators.
+ if (!it->m_table) {
+ ASSERT(!it->m_next);
+ ASSERT(!it->m_previous);
+ } else {
+ MutexLocker lock(it->m_table->m_mutex);
+ if (it->m_next) {
+ ASSERT(it->m_next->m_previous == it);
+ it->m_next->m_previous = it->m_previous;
+ }
+ if (it->m_previous) {
+ ASSERT(it->m_table->m_iterators != it);
+ ASSERT(it->m_previous->m_next == it);
+ it->m_previous->m_next = it->m_next;
+ } else {
+ ASSERT(it->m_table->m_iterators == it);
+ it->m_table->m_iterators = it->m_next;
+ }
+ }
+
+ it->m_table = 0;
+ it->m_next = 0;
+ it->m_previous = 0;
+ }
+
+#endif // CHECK_HASHTABLE_ITERATORS
+
+ // iterator adapters
+
+ template<typename HashTableType, typename ValueType> struct HashTableConstIteratorAdapter {
+ HashTableConstIteratorAdapter() {}
+ HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
+
+ const ValueType* get() const { return (const ValueType*)m_impl.get(); }
+ const ValueType& operator*() const { return *get(); }
+ const ValueType* operator->() const { return get(); }
+
+ HashTableConstIteratorAdapter& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ typename HashTableType::const_iterator m_impl;
+ };
+
+ template<typename HashTableType, typename ValueType> struct HashTableIteratorAdapter {
+ HashTableIteratorAdapter() {}
+ HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
+
+ ValueType* get() const { return (ValueType*)m_impl.get(); }
+ ValueType& operator*() const { return *get(); }
+ ValueType* operator->() const { return get(); }
+
+ HashTableIteratorAdapter& operator++() { ++m_impl; return *this; }
+ // postfix ++ intentionally omitted
+
+ operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
+ typename HashTableType::const_iterator i = m_impl;
+ return i;
+ }
+
+ typename HashTableType::iterator m_impl;
+ };
+
+ template<typename T, typename U>
+ inline bool operator==(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator!=(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator==(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ // All 4 combinations of ==, != and Const,non const.
+ template<typename T, typename U>
+ inline bool operator==(const HashTableConstIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator!=(const HashTableConstIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator==(const HashTableIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl == b.m_impl;
+ }
+
+ template<typename T, typename U>
+ inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
+ {
+ return a.m_impl != b.m_impl;
+ }
+
+} // namespace WTF
+
+#include "HashIterators.h"
+
+#endif // WTF_HashTable_h
diff --git a/Source/JavaScriptCore/wtf/HashTraits.h b/Source/JavaScriptCore/wtf/HashTraits.h
new file mode 100644
index 000000000..12e6b0699
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HashTraits.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 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_HashTraits_h
+#define WTF_HashTraits_h
+
+#include "HashFunctions.h"
+#include "StdLibExtras.h"
+#include "TypeTraits.h"
+#include <utility>
+#include <limits>
+
+namespace WTF {
+
+ class String;
+
+ template<typename T> class OwnPtr;
+ template<typename T> class PassOwnPtr;
+
+ using std::pair;
+ using std::make_pair;
+
+ template<typename T> struct HashTraits;
+
+ template<bool isInteger, typename T> struct GenericHashTraitsBase;
+
+ template<typename T> struct GenericHashTraitsBase<false, T> {
+ static const bool emptyValueIsZero = false;
+ static const bool needsDestruction = true;
+ static const int minimumTableSize = 64;
+ };
+
+ // Default integer traits disallow both 0 and -1 as keys (max value instead of -1 for unsigned).
+ template<typename T> struct GenericHashTraitsBase<true, T> : GenericHashTraitsBase<false, T> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ static void constructDeletedValue(T& slot) { slot = static_cast<T>(-1); }
+ static bool isDeletedValue(T value) { return value == static_cast<T>(-1); }
+ };
+
+ template<typename T> struct GenericHashTraits : GenericHashTraitsBase<IsInteger<T>::value, T> {
+ typedef T TraitType;
+
+ static T emptyValue() { return T(); }
+
+ // Type for functions that take ownership, such as add.
+ // The store function either not be called or called once to store something passed in.
+ // The value passed to the store function will be either PassInType or PassInType&.
+ typedef const T& PassInType;
+ static void store(const T& value, T& storage) { storage = value; }
+
+ // Type for return value of functions that transfer ownership, such as take.
+ typedef T PassOutType;
+ static PassOutType passOut(const T& value) { return value; }
+
+ // Type for return value of functions that do not transfer ownership, such as get.
+ // FIXME: We could change this type to const T& for better performance if we figured out
+ // a way to handle the return value from emptyValue, which is a temporary.
+ typedef T PeekType;
+ static PeekType peek(const T& value) { return value; }
+ };
+
+ template<typename T> struct HashTraits : GenericHashTraits<T> { };
+
+ template<typename T> struct FloatHashTraits : GenericHashTraits<T> {
+ static const bool needsDestruction = false;
+ static T emptyValue() { return std::numeric_limits<T>::infinity(); }
+ static void constructDeletedValue(T& slot) { slot = -std::numeric_limits<T>::infinity(); }
+ static bool isDeletedValue(T value) { return value == -std::numeric_limits<T>::infinity(); }
+ };
+
+ template<> struct HashTraits<float> : FloatHashTraits<float> { };
+ template<> struct HashTraits<double> : FloatHashTraits<double> { };
+
+ // Default unsigned traits disallow both 0 and max as keys -- use these traits to allow zero and disallow max - 1.
+ template<typename T> struct UnsignedWithZeroKeyHashTraits : GenericHashTraits<T> {
+ static const bool emptyValueIsZero = false;
+ static const bool needsDestruction = false;
+ static T emptyValue() { return std::numeric_limits<T>::max(); }
+ static void constructDeletedValue(T& slot) { slot = std::numeric_limits<T>::max() - 1; }
+ static bool isDeletedValue(T value) { return value == std::numeric_limits<T>::max() - 1; }
+ };
+
+ template<typename P> struct HashTraits<P*> : GenericHashTraits<P*> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ static void constructDeletedValue(P*& slot) { slot = reinterpret_cast<P*>(-1); }
+ static bool isDeletedValue(P* value) { return value == reinterpret_cast<P*>(-1); }
+ };
+
+ template<typename T> struct SimpleClassHashTraits : GenericHashTraits<T> {
+ static const bool emptyValueIsZero = true;
+ static void constructDeletedValue(T& slot) { new (NotNull, &slot) T(HashTableDeletedValue); }
+ static bool isDeletedValue(const T& value) { return value.isHashTableDeletedValue(); }
+ };
+
+ template<typename P> struct HashTraits<OwnPtr<P> > : SimpleClassHashTraits<OwnPtr<P> > {
+ static std::nullptr_t emptyValue() { return nullptr; }
+
+ typedef PassOwnPtr<P> PassInType;
+ static void store(PassOwnPtr<P> value, OwnPtr<P>& storage) { storage = value; }
+
+ typedef PassOwnPtr<P> PassOutType;
+ static PassOwnPtr<P> passOut(OwnPtr<P>& value) { return value.release(); }
+ static PassOwnPtr<P> passOut(std::nullptr_t) { return nullptr; }
+
+ typedef typename OwnPtr<P>::PtrType PeekType;
+ static PeekType peek(const OwnPtr<P>& value) { return value.get(); }
+ static PeekType peek(std::nullptr_t) { return 0; }
+ };
+
+ template<typename P> struct HashTraits<RefPtr<P> > : SimpleClassHashTraits<RefPtr<P> > {
+ typedef PassRefPtr<P> PassInType;
+ static void store(PassRefPtr<P> value, RefPtr<P>& storage) { storage = value; }
+
+ // FIXME: We should change PassOutType to PassRefPtr for better performance.
+ // FIXME: We should consider changing PeekType to a raw pointer for better performance,
+ // but then callers won't need to call get; doing so will require updating many call sites.
+ };
+
+ template<> struct HashTraits<String> : SimpleClassHashTraits<String> { };
+
+ // special traits for pairs, helpful for their use in HashMap implementation
+
+ template<typename FirstTraitsArg, typename SecondTraitsArg>
+ struct PairHashTraits : GenericHashTraits<pair<typename FirstTraitsArg::TraitType, typename SecondTraitsArg::TraitType> > {
+ typedef FirstTraitsArg FirstTraits;
+ typedef SecondTraitsArg SecondTraits;
+ typedef pair<typename FirstTraits::TraitType, typename SecondTraits::TraitType> TraitType;
+
+ static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
+ static TraitType emptyValue() { return make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
+
+ static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
+
+ static const int minimumTableSize = FirstTraits::minimumTableSize;
+
+ static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
+ static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
+ };
+
+ template<typename First, typename Second>
+ struct HashTraits<pair<First, Second> > : public PairHashTraits<HashTraits<First>, HashTraits<Second> > { };
+
+} // namespace WTF
+
+using WTF::HashTraits;
+using WTF::PairHashTraits;
+
+#endif // WTF_HashTraits_h
diff --git a/Source/JavaScriptCore/wtf/HexNumber.h b/Source/JavaScriptCore/wtf/HexNumber.h
new file mode 100644
index 000000000..8fd60323b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/HexNumber.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 Research In Motion Limited. 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 HexNumber_h
+#define HexNumber_h
+
+#include <wtf/text/StringConcatenate.h>
+
+namespace WTF {
+
+enum HexConversionMode {
+ Lowercase,
+ Uppercase
+};
+
+namespace Internal {
+
+static const char* hexDigitsForMode(HexConversionMode mode)
+{
+ static const char lowerHexDigits[17] = "0123456789abcdef";
+ static const char upperHexDigits[17] = "0123456789ABCDEF";
+ return mode == Lowercase ? lowerHexDigits : upperHexDigits;
+}
+
+}; // namespace Internal
+
+template<typename T>
+inline void appendByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ destination.append(hexDigits[byte >> 4]);
+ destination.append(hexDigits[byte & 0xF]);
+}
+
+template<typename T>
+inline void placeByteAsHexCompressIfPossible(unsigned char byte, T& destination, unsigned& index, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ if (byte >= 0x10)
+ destination[index++] = hexDigits[byte >> 4];
+ destination[index++] = hexDigits[byte & 0xF];
+}
+
+template<typename T>
+inline void placeByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ *destination++ = hexDigits[byte >> 4];
+ *destination++ = hexDigits[byte & 0xF];
+}
+
+template<typename T>
+inline void appendUnsignedAsHex(unsigned number, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ Vector<UChar, 8> result;
+ do {
+ result.prepend(hexDigits[number % 16]);
+ number >>= 4;
+ } while (number > 0);
+
+ destination.append(result.data(), result.size());
+}
+
+// Same as appendUnsignedAsHex, but using exactly 'desiredDigits' for the conversion.
+template<typename T>
+inline void appendUnsignedAsHexFixedSize(unsigned number, T& destination, unsigned desiredDigits, HexConversionMode mode = Uppercase)
+{
+ ASSERT(desiredDigits);
+
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ Vector<UChar, 8> result;
+ do {
+ result.prepend(hexDigits[number % 16]);
+ number >>= 4;
+ } while (result.size() < desiredDigits);
+
+ ASSERT(result.size() == desiredDigits);
+ destination.append(result.data(), result.size());
+}
+
+} // namespace WTF
+
+using WTF::appendByteAsHex;
+using WTF::appendUnsignedAsHex;
+using WTF::appendUnsignedAsHexFixedSize;
+using WTF::placeByteAsHex;
+using WTF::placeByteAsHexCompressIfPossible;
+using WTF::Lowercase;
+
+#endif // HexNumber_h
diff --git a/Source/JavaScriptCore/wtf/InlineASM.h b/Source/JavaScriptCore/wtf/InlineASM.h
new file mode 100644
index 000000000..c8a93f99c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/InlineASM.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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 InlineASM_h
+#define InlineASM_h
+
+#include <wtf/Platform.h>
+
+/* asm directive helpers */
+
+#if OS(DARWIN) || (OS(WINDOWS) && CPU(X86))
+#define SYMBOL_STRING(name) "_" #name
+#else
+#define SYMBOL_STRING(name) #name
+#endif
+
+#if OS(IOS)
+#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name)
+#else
+#define THUMB_FUNC_PARAM(name)
+#endif
+
+#if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64)
+#define SYMBOL_STRING_RELOCATION(name) #name "@plt"
+#elif CPU(X86) && COMPILER(MINGW)
+#define SYMBOL_STRING_RELOCATION(name) "@" #name "@4"
+#else
+#define SYMBOL_STRING_RELOCATION(name) SYMBOL_STRING(name)
+#endif
+
+#if OS(DARWIN)
+ // Mach-O platform
+#define HIDE_SYMBOL(name) ".private_extern _" #name
+#elif OS(AIX)
+ // IBM's own file format
+#define HIDE_SYMBOL(name) ".lglobl " #name
+#elif OS(LINUX) \
+ || OS(FREEBSD) \
+ || OS(OPENBSD) \
+ || OS(SOLARIS) \
+ || (OS(HPUX) && CPU(IA64)) \
+ || OS(NETBSD)
+ // ELF platform
+#define HIDE_SYMBOL(name) ".hidden " #name
+#else
+#define HIDE_SYMBOL(name)
+#endif
+
+#endif // InlineASM_h
diff --git a/Source/JavaScriptCore/wtf/Int16Array.h b/Source/JavaScriptCore/wtf/Int16Array.h
new file mode 100644
index 000000000..34a52de90
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Int16Array.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Int16Array_h
+#define Int16Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class ArrayBuffer;
+
+class Int16Array : public IntegralTypedArrayBase<short> {
+public:
+ static inline PassRefPtr<Int16Array> create(unsigned length);
+ static inline PassRefPtr<Int16Array> create(short* array, unsigned length);
+ static inline PassRefPtr<Int16Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<short>* array, unsigned offset) { return TypedArrayBase<short>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<short>::set(index, value); }
+
+ inline PassRefPtr<Int16Array> subarray(int start) const;
+ inline PassRefPtr<Int16Array> subarray(int start, int end) const;
+
+private:
+ inline Int16Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<short>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isShortArray() const { return true; }
+};
+
+PassRefPtr<Int16Array> Int16Array::create(unsigned length)
+{
+ return TypedArrayBase<short>::create<Int16Array>(length);
+}
+
+PassRefPtr<Int16Array> Int16Array::create(short* array, unsigned length)
+{
+ return TypedArrayBase<short>::create<Int16Array>(array, length);
+}
+
+PassRefPtr<Int16Array> Int16Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<short>::create<Int16Array>(buffer, byteOffset, length);
+}
+
+Int16Array::Int16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : IntegralTypedArrayBase<short>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Int16Array> Int16Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Int16Array> Int16Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Int16Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Int16Array;
+
+#endif // Int16Array_h
diff --git a/Source/JavaScriptCore/wtf/Int32Array.h b/Source/JavaScriptCore/wtf/Int32Array.h
new file mode 100644
index 000000000..0b61457b3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Int32Array.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Int32Array_h
+#define Int32Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class Int32Array : public IntegralTypedArrayBase<int> {
+public:
+ static inline PassRefPtr<Int32Array> create(unsigned length);
+ static inline PassRefPtr<Int32Array> create(int* array, unsigned length);
+ static inline PassRefPtr<Int32Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<int>* array, unsigned offset) { return TypedArrayBase<int>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<int>::set(index, value); }
+
+ inline PassRefPtr<Int32Array> subarray(int start) const;
+ inline PassRefPtr<Int32Array> subarray(int start, int end) const;
+
+private:
+ inline Int32Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<int>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isIntArray() const { return true; }
+};
+
+PassRefPtr<Int32Array> Int32Array::create(unsigned length)
+{
+ return TypedArrayBase<int>::create<Int32Array>(length);
+}
+
+PassRefPtr<Int32Array> Int32Array::create(int* array, unsigned length)
+{
+ return TypedArrayBase<int>::create<Int32Array>(array, length);
+}
+
+PassRefPtr<Int32Array> Int32Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<int>::create<Int32Array>(buffer, byteOffset, length);
+}
+
+Int32Array::Int32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : IntegralTypedArrayBase<int>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Int32Array> Int32Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Int32Array> Int32Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Int32Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Int32Array;
+
+#endif // Int32Array_h
diff --git a/Source/JavaScriptCore/wtf/Int8Array.h b/Source/JavaScriptCore/wtf/Int8Array.h
new file mode 100644
index 000000000..6db7b6899
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Int8Array.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Int8Array_h
+#define Int8Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class ArrayBuffer;
+
+class Int8Array : public IntegralTypedArrayBase<signed char> {
+public:
+ static inline PassRefPtr<Int8Array> create(unsigned length);
+ static inline PassRefPtr<Int8Array> create(signed char* array, unsigned length);
+ static inline PassRefPtr<Int8Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<signed char>* array, unsigned offset) { return TypedArrayBase<signed char>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<signed char>::set(index, value); }
+
+ inline PassRefPtr<Int8Array> subarray(int start) const;
+ inline PassRefPtr<Int8Array> subarray(int start, int end) const;
+
+private:
+ inline Int8Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<signed char>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isByteArray() const { return true; }
+};
+
+PassRefPtr<Int8Array> Int8Array::create(unsigned length)
+{
+ return TypedArrayBase<signed char>::create<Int8Array>(length);
+}
+
+PassRefPtr<Int8Array> Int8Array::create(signed char* array, unsigned length)
+{
+ return TypedArrayBase<signed char>::create<Int8Array>(array, length);
+}
+
+PassRefPtr<Int8Array> Int8Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<signed char>::create<Int8Array>(buffer, byteOffset, length);
+}
+
+Int8Array::Int8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : IntegralTypedArrayBase<signed char>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Int8Array> Int8Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Int8Array> Int8Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Int8Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Int8Array;
+
+#endif // Int8Array_h
diff --git a/Source/JavaScriptCore/wtf/IntegralTypedArrayBase.h b/Source/JavaScriptCore/wtf/IntegralTypedArrayBase.h
new file mode 100644
index 000000000..48f82a361
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/IntegralTypedArrayBase.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 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 IntegralTypedArrayBase_h
+#define IntegralTypedArrayBase_h
+
+#include "TypedArrayBase.h"
+#include <limits>
+#include <wtf/MathExtras.h>
+
+// Base class for all WebGL<T>Array types holding integral
+// (non-floating-point) values.
+
+namespace WTF {
+
+template <typename T>
+class IntegralTypedArrayBase : public TypedArrayBase<T> {
+ public:
+ void set(unsigned index, double value)
+ {
+ if (index >= TypedArrayBase<T>::m_length)
+ return;
+ if (isnan(value)) // Clamp NaN to 0
+ value = 0;
+ // The double cast is necessary to get the correct wrapping
+ // for out-of-range values with Int32Array and Uint32Array.
+ TypedArrayBase<T>::data()[index] = static_cast<T>(static_cast<int64_t>(value));
+ }
+
+ // Invoked by the indexed getter. Does not perform range checks; caller
+ // is responsible for doing so and returning undefined as necessary.
+ T item(unsigned index) const
+ {
+ ASSERT(index < TypedArrayBase<T>::m_length);
+ return TypedArrayBase<T>::data()[index];
+ }
+
+ protected:
+ IntegralTypedArrayBase(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : TypedArrayBase<T>(buffer, byteOffset, length)
+ {
+ }
+};
+
+} // namespace WTF
+
+using WTF::IntegralTypedArrayBase;
+
+#endif // IntegralTypedArrayBase_h
diff --git a/Source/JavaScriptCore/wtf/ListHashSet.h b/Source/JavaScriptCore/wtf/ListHashSet.h
new file mode 100644
index 000000000..3b413406d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ListHashSet.h
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.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_ListHashSet_h
+#define WTF_ListHashSet_h
+
+#include "HashSet.h"
+#include "OwnPtr.h"
+#include "PassOwnPtr.h"
+
+namespace WTF {
+
+ // ListHashSet: Just like HashSet, this class provides a Set
+ // interface - a collection of unique objects with O(1) insertion,
+ // removal and test for containership. However, it also has an
+ // order - iterating it will always give back values in the order
+ // in which they are added.
+
+ // In theory it would be possible to add prepend, insertAfter
+ // and an append that moves the element to the end even if already present,
+ // but unclear yet if these are needed.
+
+ template<typename Value, size_t inlineCapacity, typename HashFunctions> class ListHashSet;
+
+ template<typename Value, size_t inlineCapacity, typename HashFunctions>
+ void deleteAllValues(const ListHashSet<Value, inlineCapacity, HashFunctions>&);
+
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator;
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator;
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetReverseIterator;
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstReverseIterator;
+
+ template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode;
+ template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator;
+
+ template<typename HashArg> struct ListHashSetNodeHashFunctions;
+ template<typename HashArg> struct ListHashSetTranslator;
+
+ template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef ListHashSetNode<ValueArg, inlineCapacity> Node;
+ typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator;
+
+ typedef HashTraits<Node*> NodeTraits;
+ typedef ListHashSetNodeHashFunctions<HashArg> NodeHash;
+ typedef ListHashSetTranslator<HashArg> BaseTranslator;
+
+ typedef HashTable<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplType;
+ typedef HashTableIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplTypeIterator;
+ typedef HashTableConstIterator<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> ImplTypeConstIterator;
+
+ typedef HashArg HashFunctions;
+
+ public:
+ typedef ValueArg ValueType;
+
+ typedef ListHashSetIterator<ValueType, inlineCapacity, HashArg> iterator;
+ typedef ListHashSetConstIterator<ValueType, inlineCapacity, HashArg> const_iterator;
+ friend class ListHashSetConstIterator<ValueType, inlineCapacity, HashArg>;
+
+ typedef ListHashSetReverseIterator<ValueType, inlineCapacity, HashArg> reverse_iterator;
+ typedef ListHashSetConstReverseIterator<ValueType, inlineCapacity, HashArg> const_reverse_iterator;
+ friend class ListHashSetConstReverseIterator<ValueType, inlineCapacity, HashArg>;
+
+ ListHashSet();
+ ListHashSet(const ListHashSet&);
+ ListHashSet& operator=(const ListHashSet&);
+ ~ListHashSet();
+
+ void swap(ListHashSet&);
+
+ int size() const;
+ int capacity() const;
+ bool isEmpty() const;
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ reverse_iterator rbegin();
+ reverse_iterator rend();
+ const_reverse_iterator rbegin() const;
+ const_reverse_iterator rend() const;
+
+ ValueType& first();
+ const ValueType& first() const;
+
+ ValueType& last();
+ const ValueType& last() const;
+ void removeLast();
+
+ 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
+ // with some other type, to avoid the cost of type conversion.
+ // The HashTranslator interface is defined in HashSet.
+ // FIXME: We should reverse the order of the template arguments so that callers
+ // can just pass the translator let the compiler deduce 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> bool contains(const T&) const;
+
+ // The return value of add is a pair of an iterator to the new value's location,
+ // and a bool that is true if an new entry was added.
+ pair<iterator, bool> add(const ValueType&);
+
+ pair<iterator, bool> insertBefore(const ValueType& beforeValue, const ValueType& newValue);
+ pair<iterator, bool> insertBefore(iterator it, const ValueType&);
+
+ void remove(const ValueType&);
+ void remove(iterator);
+ void clear();
+
+ private:
+ void unlinkAndDelete(Node*);
+ void appendNode(Node*);
+ void insertNodeBefore(Node* beforeNode, Node* newNode);
+ void deleteAllNodes();
+
+ iterator makeIterator(Node*);
+ const_iterator makeConstIterator(Node*) const;
+ reverse_iterator makeReverseIterator(Node*);
+ const_reverse_iterator makeConstReverseIterator(Node*) const;
+
+ friend void deleteAllValues<>(const ListHashSet&);
+
+ ImplType m_impl;
+ Node* m_head;
+ Node* m_tail;
+ OwnPtr<NodeAllocator> m_allocator;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator {
+ typedef ListHashSetNode<ValueArg, inlineCapacity> Node;
+ typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator;
+
+ ListHashSetNodeAllocator()
+ : m_freeList(pool())
+ , m_isDoneWithInitialFreeList(false)
+ {
+ memset(m_pool.pool, 0, sizeof(m_pool.pool));
+ }
+
+ Node* allocate()
+ {
+ Node* result = m_freeList;
+
+ if (!result)
+ return static_cast<Node*>(fastMalloc(sizeof(Node)));
+
+ ASSERT(!result->m_isAllocated);
+
+ Node* next = result->m_next;
+ ASSERT(!next || !next->m_isAllocated);
+ if (!next && !m_isDoneWithInitialFreeList) {
+ next = result + 1;
+ if (next == pastPool()) {
+ m_isDoneWithInitialFreeList = true;
+ next = 0;
+ } else {
+ ASSERT(inPool(next));
+ ASSERT(!next->m_isAllocated);
+ }
+ }
+ m_freeList = next;
+
+ return result;
+ }
+
+ void deallocate(Node* node)
+ {
+ if (inPool(node)) {
+#ifndef NDEBUG
+ node->m_isAllocated = false;
+#endif
+ node->m_next = m_freeList;
+ m_freeList = node;
+ return;
+ }
+
+ fastFree(node);
+ }
+
+ private:
+ Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.pool); }
+ Node* pastPool() { return pool() + m_poolSize; }
+
+ bool inPool(Node* node)
+ {
+ return node >= pool() && node < pastPool();
+ }
+
+ Node* m_freeList;
+ bool m_isDoneWithInitialFreeList;
+ static const size_t m_poolSize = inlineCapacity;
+ union {
+ char pool[sizeof(Node) * m_poolSize];
+ double forAlignment;
+ } m_pool;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNode {
+ typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator;
+
+ ListHashSetNode(ValueArg value)
+ : m_value(value)
+ , m_prev(0)
+ , m_next(0)
+#ifndef NDEBUG
+ , m_isAllocated(true)
+#endif
+ {
+ }
+
+ void* operator new(size_t, NodeAllocator* allocator)
+ {
+ return allocator->allocate();
+ }
+ void destroy(NodeAllocator* allocator)
+ {
+ this->~ListHashSetNode();
+ allocator->deallocate(this);
+ }
+
+ ValueArg m_value;
+ ListHashSetNode* m_prev;
+ ListHashSetNode* m_next;
+
+#ifndef NDEBUG
+ bool m_isAllocated;
+#endif
+ };
+
+ template<typename HashArg> struct ListHashSetNodeHashFunctions {
+ template<typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); }
+ template<typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetIterator {
+ private:
+ 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, inlineCapacity, HashArg>;
+
+ ListHashSetIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { }
+
+ public:
+ ListHashSetIterator() { }
+
+ // default copy, assignment and destructor are OK
+
+ PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ iterator& operator++() { ++m_iterator; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ iterator& operator--() { --m_iterator; return *this; }
+
+ // postfix -- intentionally omitted
+
+ // Comparison.
+ bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
+ bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
+
+ operator const_iterator() const { return m_iterator; }
+
+ private:
+ Node* node() { return m_iterator.node(); }
+
+ const_iterator m_iterator;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstIterator {
+ private:
+ 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, inlineCapacity, HashArg>;
+ friend class ListHashSetIterator<ValueArg, inlineCapacity, HashArg>;
+
+ ListHashSetConstIterator(const ListHashSetType* set, Node* position)
+ : m_set(set)
+ , m_position(position)
+ {
+ }
+
+ public:
+ ListHashSetConstIterator()
+ {
+ }
+
+ PointerType get() const
+ {
+ return &m_position->m_value;
+ }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ const_iterator& operator++()
+ {
+ ASSERT(m_position != 0);
+ m_position = m_position->m_next;
+ return *this;
+ }
+
+ // postfix ++ intentionally omitted
+
+ const_iterator& operator--()
+ {
+ ASSERT(m_position != m_set->m_head);
+ if (!m_position)
+ m_position = m_set->m_tail;
+ else
+ m_position = m_position->m_prev;
+ return *this;
+ }
+
+ // postfix -- intentionally omitted
+
+ // Comparison.
+ bool operator==(const const_iterator& other) const
+ {
+ return m_position == other.m_position;
+ }
+ bool operator!=(const const_iterator& other) const
+ {
+ return m_position != other.m_position;
+ }
+
+ private:
+ Node* node() { return m_position; }
+
+ const ListHashSetType* m_set;
+ Node* m_position;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetReverseIterator {
+ private:
+ typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType;
+ typedef ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg> reverse_iterator;
+ typedef ListHashSetConstIterator<ValueArg, inlineCapacity, HashArg> const_reverse_iterator;
+ typedef ListHashSetNode<ValueArg, inlineCapacity> Node;
+ typedef ValueArg ValueType;
+ typedef ValueType& ReferenceType;
+ typedef ValueType* PointerType;
+
+ friend class ListHashSet<ValueArg, inlineCapacity, HashArg>;
+
+ ListHashSetReverseIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { }
+
+ public:
+ ListHashSetReverseIterator() { }
+
+ // default copy, assignment and destructor are OK
+
+ PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ reverse_iterator& operator++() { ++m_iterator; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ reverse_iterator& operator--() { --m_iterator; return *this; }
+
+ // postfix -- intentionally omitted
+
+ // Comparison.
+ bool operator==(const reverse_iterator& other) const { return m_iterator == other.m_iterator; }
+ bool operator!=(const reverse_iterator& other) const { return m_iterator != other.m_iterator; }
+
+ operator const_reverse_iterator() const { return m_iterator; }
+
+ private:
+ Node* node() { return m_iterator.node(); }
+
+ const_reverse_iterator m_iterator;
+ };
+
+ template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSetConstReverseIterator {
+ private:
+ typedef ListHashSet<ValueArg, inlineCapacity, HashArg> ListHashSetType;
+ typedef ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg> reverse_iterator;
+ typedef ListHashSetConstReverseIterator<ValueArg, inlineCapacity, HashArg> const_reverse_iterator;
+ typedef ListHashSetNode<ValueArg, inlineCapacity> Node;
+ typedef ValueArg ValueType;
+ typedef const ValueType& ReferenceType;
+ typedef const ValueType* PointerType;
+
+ friend class ListHashSet<ValueArg, inlineCapacity, HashArg>;
+ friend class ListHashSetReverseIterator<ValueArg, inlineCapacity, HashArg>;
+
+ ListHashSetConstReverseIterator(const ListHashSetType* set, Node* position)
+ : m_set(set)
+ , m_position(position)
+ {
+ }
+
+ public:
+ ListHashSetConstReverseIterator()
+ {
+ }
+
+ PointerType get() const
+ {
+ return &m_position->m_value;
+ }
+ ReferenceType operator*() const { return *get(); }
+ PointerType operator->() const { return get(); }
+
+ const_reverse_iterator& operator++()
+ {
+ ASSERT(m_position != 0);
+ m_position = m_position->m_prev;
+ return *this;
+ }
+
+ // postfix ++ intentionally omitted
+
+ const_reverse_iterator& operator--()
+ {
+ ASSERT(m_position != m_set->m_tail);
+ if (!m_position)
+ m_position = m_set->m_head;
+ else
+ m_position = m_position->m_next;
+ return *this;
+ }
+
+ // postfix -- intentionally omitted
+
+ // Comparison.
+ bool operator==(const const_reverse_iterator& other) const
+ {
+ return m_position == other.m_position;
+ }
+ bool operator!=(const const_reverse_iterator& other) const
+ {
+ return m_position != other.m_position;
+ }
+
+ private:
+ Node* node() { return m_position; }
+
+ const ListHashSetType* m_set;
+ Node* m_position;
+ };
+
+ template<typename HashFunctions>
+ struct ListHashSetTranslator {
+ template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); }
+ template<typename T, typename U, typename V> static void translate(T*& location, const U& key, const V& allocator)
+ {
+ location = new (allocator) T(key);
+ }
+ };
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSet<T, inlineCapacity, U>::ListHashSet()
+ : m_head(0)
+ , m_tail(0)
+ , m_allocator(adoptPtr(new NodeAllocator))
+ {
+ }
+
+ 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(adoptPtr(new NodeAllocator))
+ {
+ const_iterator end = other.end();
+ for (const_iterator it = other.begin(); it != end; ++it)
+ add(*it);
+ }
+
+ 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, 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);
+ std::swap(m_tail, other.m_tail);
+ m_allocator.swap(other.m_allocator);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSet<T, inlineCapacity, U>::~ListHashSet()
+ {
+ deleteAllNodes();
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline int ListHashSet<T, inlineCapacity, U>::size() const
+ {
+ return m_impl.size();
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline int ListHashSet<T, inlineCapacity, U>::capacity() const
+ {
+ return m_impl.capacity();
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline bool ListHashSet<T, inlineCapacity, U>::isEmpty() const
+ {
+ return m_impl.isEmpty();
+ }
+
+ 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, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::end()
+ {
+ return makeIterator(0);
+ }
+
+ 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, 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, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::reverse_iterator ListHashSet<T, inlineCapacity, U>::rbegin()
+ {
+ return makeReverseIterator(m_tail);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::reverse_iterator ListHashSet<T, inlineCapacity, U>::rend()
+ {
+ return makeReverseIterator(0);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::const_reverse_iterator ListHashSet<T, inlineCapacity, U>::rbegin() const
+ {
+ return makeConstReverseIterator(m_tail);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::const_reverse_iterator ListHashSet<T, inlineCapacity, U>::rend() const
+ {
+ return makeConstReverseIterator(0);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline T& ListHashSet<T, inlineCapacity, U>::first()
+ {
+ ASSERT(!isEmpty());
+ return m_head->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline const T& ListHashSet<T, inlineCapacity, U>::first() const
+ {
+ ASSERT(!isEmpty());
+ return m_head->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline T& ListHashSet<T, inlineCapacity, U>::last()
+ {
+ ASSERT(!isEmpty());
+ return m_tail->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline const T& ListHashSet<T, inlineCapacity, U>::last() const
+ {
+ ASSERT(!isEmpty());
+ return m_tail->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline void ListHashSet<T, inlineCapacity, U>::removeLast()
+ {
+ ASSERT(!isEmpty());
+ m_impl.remove(m_tail);
+ unlinkAndDelete(m_tail);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value)
+ {
+ ImplTypeIterator it = m_impl.template find<BaseTranslator>(value);
+ if (it == m_impl.end())
+ return end();
+ return makeIterator(*it);
+ }
+
+ 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
+ {
+ ImplTypeConstIterator it = m_impl.template find<BaseTranslator>(value);
+ if (it == m_impl.end())
+ return end();
+ return makeConstIterator(*it);
+ }
+
+ template<typename Translator>
+ struct ListHashSetTranslatorAdapter {
+ template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); }
+ };
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline typename ListHashSet<ValueType, inlineCapacity, U>::iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value)
+ {
+ ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value);
+ if (it == m_impl.end())
+ return end();
+ return makeIterator(*it);
+ }
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline typename ListHashSet<ValueType, inlineCapacity, U>::const_iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value) const
+ {
+ ImplTypeConstIterator it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator> >(value);
+ if (it == m_impl.end())
+ return end();
+ return makeConstIterator(*it);
+ }
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline bool ListHashSet<ValueType, inlineCapacity, U>::contains(const T& value) const
+ {
+ return m_impl.template contains<ListHashSetTranslatorAdapter<HashTranslator> >(value);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline bool ListHashSet<T, inlineCapacity, U>::contains(const ValueType& value) const
+ {
+ return m_impl.template contains<BaseTranslator>(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)
+ {
+ pair<typename ImplType::iterator, bool> result = m_impl.template add<BaseTranslator>(value, m_allocator.get());
+ if (result.second)
+ appendNode(*result.first);
+ return std::make_pair(makeIterator(*result.first), result.second);
+ }
+
+ 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)
+ {
+ pair<typename ImplType::iterator, bool> result = m_impl.template add<BaseTranslator>(newValue, m_allocator.get());
+ if (result.second)
+ insertNodeBefore(it.node(), *result.first);
+ return std::make_pair(makeIterator(*result.first), result.second);
+
+ }
+
+ 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, size_t inlineCapacity, typename U>
+ inline void ListHashSet<T, inlineCapacity, U>::remove(iterator it)
+ {
+ if (it == end())
+ return;
+ m_impl.remove(it.node());
+ unlinkAndDelete(it.node());
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline void ListHashSet<T, inlineCapacity, U>::remove(const ValueType& value)
+ {
+ remove(find(value));
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline void ListHashSet<T, inlineCapacity, U>::clear()
+ {
+ deleteAllNodes();
+ m_impl.clear();
+ m_head = 0;
+ m_tail = 0;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ void ListHashSet<T, inlineCapacity, U>::unlinkAndDelete(Node* node)
+ {
+ if (!node->m_prev) {
+ ASSERT(node == m_head);
+ m_head = node->m_next;
+ } else {
+ ASSERT(node != m_head);
+ node->m_prev->m_next = node->m_next;
+ }
+
+ if (!node->m_next) {
+ ASSERT(node == m_tail);
+ m_tail = node->m_prev;
+ } else {
+ ASSERT(node != m_tail);
+ node->m_next->m_prev = node->m_prev;
+ }
+
+ node->destroy(m_allocator.get());
+ }
+
+ 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;
+
+ if (m_tail) {
+ ASSERT(m_head);
+ m_tail->m_next = node;
+ } else {
+ ASSERT(!m_head);
+ m_head = node;
+ }
+
+ m_tail = node;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ void ListHashSet<T, inlineCapacity, U>::insertNodeBefore(Node* beforeNode, Node* newNode)
+ {
+ if (!beforeNode)
+ return appendNode(newNode);
+
+ newNode->m_next = beforeNode;
+ newNode->m_prev = beforeNode->m_prev;
+ if (beforeNode->m_prev)
+ beforeNode->m_prev->m_next = newNode;
+ beforeNode->m_prev = newNode;
+
+ if (!newNode->m_prev)
+ m_head = newNode;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ void ListHashSet<T, inlineCapacity, U>::deleteAllNodes()
+ {
+ if (!m_head)
+ return;
+
+ for (Node* node = m_head, *next = m_head->m_next; node; node = next, next = node ? node->m_next : 0)
+ node->destroy(m_allocator.get());
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSetReverseIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeReverseIterator(Node* position)
+ {
+ return ListHashSetReverseIterator<T, inlineCapacity, U>(this, position);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSetConstReverseIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstReverseIterator(Node* position) const
+ {
+ return ListHashSetConstReverseIterator<T, inlineCapacity, U>(this, position);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSetIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeIterator(Node* position)
+ {
+ return ListHashSetIterator<T, inlineCapacity, U>(this, position);
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline ListHashSetConstIterator<T, inlineCapacity, U> ListHashSet<T, inlineCapacity, U>::makeConstIterator(Node* position) const
+ {
+ return ListHashSetConstIterator<T, inlineCapacity, U>(this, position);
+ }
+ template<bool, typename ValueType, typename HashTableType>
+ void deleteAllValues(HashTableType& collection)
+ {
+ typedef typename HashTableType::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete (*it)->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline void deleteAllValues(const ListHashSet<T, inlineCapacity, U>& collection)
+ {
+ deleteAllValues<true, typename ListHashSet<T, inlineCapacity, U>::ValueType>(collection.m_impl);
+ }
+
+} // namespace WTF
+
+using WTF::ListHashSet;
+
+#endif /* WTF_ListHashSet_h */
diff --git a/Source/JavaScriptCore/wtf/ListRefPtr.h b/Source/JavaScriptCore/wtf/ListRefPtr.h
new file mode 100644
index 000000000..4ba0632d7
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ListRefPtr.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 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 WTF_ListRefPtr_h
+#define WTF_ListRefPtr_h
+
+#include <wtf/RefPtr.h>
+
+namespace WTF {
+
+ // Specialized version of RefPtr desgined for use in singly-linked lists.
+ // Derefs the list iteratively to avoid recursive derefing that can overflow the stack.
+ template <typename T> class ListRefPtr : public RefPtr<T> {
+ public:
+ ListRefPtr() : RefPtr<T>() {}
+ ListRefPtr(T* ptr) : RefPtr<T>(ptr) {}
+ ListRefPtr(const RefPtr<T>& o) : RefPtr<T>(o) {}
+ // see comment in PassRefPtr.h for why this takes const reference
+ template <typename U> ListRefPtr(const PassRefPtr<U>& o) : RefPtr<T>(o) {}
+
+ ~ListRefPtr()
+ {
+ RefPtr<T> reaper = this->release();
+ while (reaper && reaper->hasOneRef())
+ reaper = reaper->releaseNext(); // implicitly protects reaper->next, then derefs reaper
+ }
+
+ ListRefPtr& operator=(T* optr) { RefPtr<T>::operator=(optr); return *this; }
+ ListRefPtr& operator=(const RefPtr<T>& o) { RefPtr<T>::operator=(o); return *this; }
+ ListRefPtr& operator=(const PassRefPtr<T>& o) { RefPtr<T>::operator=(o); return *this; }
+ template <typename U> ListRefPtr& operator=(const RefPtr<U>& o) { RefPtr<T>::operator=(o); return *this; }
+ template <typename U> ListRefPtr& operator=(const PassRefPtr<U>& o) { RefPtr<T>::operator=(o); return *this; }
+ };
+
+ template <typename T> inline T* getPtr(const ListRefPtr<T>& p)
+ {
+ return p.get();
+ }
+
+} // namespace WTF
+
+using WTF::ListRefPtr;
+
+#endif // WTF_ListRefPtr_h
diff --git a/Source/JavaScriptCore/wtf/Locker.h b/Source/JavaScriptCore/wtf/Locker.h
new file mode 100644
index 000000000..c465b99ea
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Locker.h
@@ -0,0 +1,48 @@
+/*
+ * 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 Locker_h
+#define Locker_h
+
+#include <wtf/Noncopyable.h>
+
+namespace WTF {
+
+template <typename T> class Locker {
+ WTF_MAKE_NONCOPYABLE(Locker);
+public:
+ Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
+ ~Locker() { m_lockable.unlock(); }
+private:
+ T& m_lockable;
+};
+
+}
+
+using WTF::Locker;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/MD5.cpp b/Source/JavaScriptCore/wtf/MD5.cpp
new file mode 100644
index 000000000..07bbadd9f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MD5.cpp
@@ -0,0 +1,309 @@
+// 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()
+{
+ // FIXME: Move unit tests somewhere outside the constructor. See bug 55853.
+ 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/Source/JavaScriptCore/wtf/MD5.h b/Source/JavaScriptCore/wtf/MD5.h
new file mode 100644
index 000000000..3caa810ba
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/MainThread.cpp b/Source/JavaScriptCore/wtf/MainThread.cpp
new file mode 100644
index 000000000..915126589
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MainThread.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2007, 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.
+ */
+
+#include "config.h"
+#include "MainThread.h"
+
+#include "CurrentTime.h"
+#include "Deque.h"
+#include "Functional.h"
+#include "StdLibExtras.h"
+#include "Threading.h"
+
+#if PLATFORM(CHROMIUM)
+#error Chromium uses a different main thread implementation
+#endif
+
+namespace WTF {
+
+struct FunctionWithContext {
+ MainThreadFunction* function;
+ void* context;
+ ThreadCondition* syncFlag;
+
+ FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0)
+ : function(function)
+ , context(context)
+ , 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)
+static ThreadIdentifier mainThreadIdentifier;
+#endif
+
+static Mutex& mainThreadFunctionQueueMutex()
+{
+ DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
+ return staticMutex;
+}
+
+static FunctionQueue& functionQueue()
+{
+ DEFINE_STATIC_LOCAL(FunctionQueue, staticFunctionQueue, ());
+ return staticFunctionQueue;
+}
+
+
+#if !PLATFORM(MAC)
+
+void initializeMainThread()
+{
+ static bool initializedMainThread;
+ if (initializedMainThread)
+ return;
+ initializedMainThread = true;
+
+ mainThreadIdentifier = currentThread();
+
+ 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;
+
+void dispatchFunctionsFromMainThread()
+{
+ ASSERT(isMainThread());
+
+ if (callbacksPaused)
+ return;
+
+ double startTime = currentTime();
+
+ FunctionWithContext invocation;
+ while (true) {
+ {
+ MutexLocker locker(mainThreadFunctionQueueMutex());
+ if (!functionQueue().size())
+ break;
+ invocation = functionQueue().takeFirst();
+ }
+
+ invocation.function(invocation.context);
+ if (invocation.syncFlag) {
+ MutexLocker locker(mainThreadFunctionQueueMutex());
+ invocation.syncFlag->signal();
+ }
+
+ // If we are running accumulated functions for too long so UI may become unresponsive, we need to
+ // yield so the user input can be processed. Otherwise user may not be able to even close the window.
+ // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
+ // allows input events to be processed before we are back here.
+ if (currentTime() - startTime > maxRunLoopSuspensionTime) {
+ scheduleDispatchFunctionsOnMainThread();
+ break;
+ }
+ }
+}
+
+void callOnMainThread(MainThreadFunction* function, void* context)
+{
+ ASSERT(function);
+ bool needToSchedule = false;
+ {
+ MutexLocker locker(mainThreadFunctionQueueMutex());
+ needToSchedule = functionQueue().size() == 0;
+ functionQueue().append(FunctionWithContext(function, context));
+ }
+ if (needToSchedule)
+ scheduleDispatchFunctionsOnMainThread();
+}
+
+void callOnMainThreadAndWait(MainThreadFunction* function, void* context)
+{
+ ASSERT(function);
+
+ if (isMainThread()) {
+ function(context);
+ return;
+ }
+
+ ThreadCondition syncFlag;
+ Mutex& functionQueueMutex = mainThreadFunctionQueueMutex();
+ MutexLocker locker(functionQueueMutex);
+ functionQueue().append(FunctionWithContext(function, context, &syncFlag));
+ if (functionQueue().size() == 1)
+ scheduleDispatchFunctionsOnMainThread();
+ 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);
+ }
+}
+
+static void callFunctionObject(void* context)
+{
+ Function<void ()>* function = static_cast<Function<void ()>*>(context);
+ (*function)();
+ delete function;
+}
+
+void callOnMainThread(const Function<void ()>& function)
+{
+ callOnMainThread(callFunctionObject, new Function<void ()>(function));
+}
+
+void setMainThreadCallbacksPaused(bool paused)
+{
+ ASSERT(isMainThread());
+
+ if (callbacksPaused == paused)
+ return;
+
+ callbacksPaused = paused;
+
+ if (!callbacksPaused)
+ scheduleDispatchFunctionsOnMainThread();
+}
+
+#if !PLATFORM(MAC)
+bool isMainThread()
+{
+ return currentThread() == mainThreadIdentifier;
+}
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/MainThread.h b/Source/JavaScriptCore/wtf/MainThread.h
new file mode 100644
index 000000000..c153d1eba
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MainThread.h
@@ -0,0 +1,85 @@
+/*
+ * 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 MainThread_h
+#define MainThread_h
+
+#include "Platform.h"
+
+#include <stdint.h>
+
+namespace WTF {
+
+typedef uint32_t ThreadIdentifier;
+typedef void MainThreadFunction(void*);
+
+// Must be called from the main thread.
+void initializeMainThread();
+
+void callOnMainThread(MainThreadFunction*, void* context);
+void callOnMainThreadAndWait(MainThreadFunction*, void* context);
+void cancelCallOnMainThread(MainThreadFunction*, void* context);
+
+template<typename> class Function;
+void callOnMainThread(const Function<void ()>&);
+
+void setMainThreadCallbacksPaused(bool paused);
+
+bool isMainThread();
+#if ENABLE(PARALLEL_GC)
+void registerGCThread();
+bool isMainThreadOrGCThread();
+#elif PLATFORM(MAC)
+bool isMainThreadOrGCThread();
+#else
+inline bool isMainThreadOrGCThread() { return isMainThread(); }
+#endif
+
+// NOTE: these functions are internal to the callOnMainThread implementation.
+void initializeMainThreadPlatform();
+void scheduleDispatchFunctionsOnMainThread();
+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;
+using WTF::isMainThreadOrGCThread;
+#endif // MainThread_h
diff --git a/Source/JavaScriptCore/wtf/MallocZoneSupport.h b/Source/JavaScriptCore/wtf/MallocZoneSupport.h
new file mode 100644
index 000000000..4332e40b8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MallocZoneSupport.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 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 MallocZoneSupport_h
+#define MallocZoneSupport_h
+
+#include <malloc/malloc.h>
+
+namespace WTF {
+
+class RemoteMemoryReader {
+ task_t m_task;
+ memory_reader_t* m_reader;
+
+public:
+ RemoteMemoryReader(task_t task, memory_reader_t* reader)
+ : m_task(task)
+ , m_reader(reader)
+ { }
+
+ void* operator()(vm_address_t address, size_t size) const
+ {
+ void* output;
+ kern_return_t err = (*m_reader)(m_task, address, size, static_cast<void**>(&output));
+ if (err)
+ output = 0;
+ return output;
+ }
+
+ template <typename T>
+ T* operator()(T* address, size_t size=sizeof(T)) const
+ {
+ return static_cast<T*>((*this)(reinterpret_cast<vm_address_t>(address), size));
+ }
+
+ template <typename T>
+ T* nextEntryInLinkedList(T** address) const
+ {
+ T** output = (*this)(address);
+ if (!output)
+ return 0;
+ return *output;
+ }
+};
+
+} // namespace WTF
+
+#endif // MallocZoneSupport_h
diff --git a/Source/JavaScriptCore/wtf/MathExtras.h b/Source/JavaScriptCore/wtf/MathExtras.h
new file mode 100644
index 000000000..e8ebd6ba1
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MathExtras.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2006, 2007, 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 WTF_MathExtras_h
+#define WTF_MathExtras_h
+
+#include <algorithm>
+#include <cmath>
+#include <float.h>
+#include <limits>
+#include <stdint.h>
+#include <stdlib.h>
+#include <wtf/StdLibExtras.h>
+
+#if OS(SOLARIS)
+#include <ieeefp.h>
+#endif
+
+#if OS(OPENBSD)
+#include <sys/types.h>
+#include <machine/ieee.h>
+#endif
+
+#if COMPILER(MSVC)
+#if OS(WINCE)
+#include <stdlib.h>
+#endif
+#include <limits>
+#endif
+
+#if OS(QNX)
+// FIXME: Look into a way to have cmath import its functions into both the standard and global
+// namespace. For now, we include math.h since the QNX cmath header only imports its functions
+// into the standard namespace.
+#include <math.h>
+#endif
+
+#ifndef M_PI
+const double piDouble = 3.14159265358979323846;
+const float piFloat = 3.14159265358979323846f;
+#else
+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;
+#else
+const double piOverFourDouble = M_PI_4;
+const float piOverFourFloat = static_cast<float>(M_PI_4);
+#endif
+
+#if OS(DARWIN)
+
+// Work around a bug in the Mac OS X libc where ceil(-0.1) return +0.
+inline double wtf_ceil(double x) { return copysign(ceil(x), x); }
+
+#define ceil(x) wtf_ceil(x)
+
+#endif
+
+#if OS(SOLARIS)
+
+#ifndef isfinite
+inline bool isfinite(double x) { return finite(x) && !isnand(x); }
+#endif
+#ifndef isinf
+inline bool isinf(double x) { return !finite(x) && !isnand(x); }
+#endif
+#ifndef signbit
+inline bool signbit(double x) { return copysign(1.0, x) < 0; }
+#endif
+
+#endif
+
+#if OS(OPENBSD)
+
+#ifndef isfinite
+inline bool isfinite(double x) { return finite(x); }
+#endif
+#ifndef signbit
+inline bool signbit(double x) { struct ieee_double *p = (struct ieee_double *)&x; return p->dbl_sign; }
+#endif
+
+#endif
+
+#if COMPILER(MSVC) || (COMPILER(RVCT) && !(RVCT_VERSION_AT_LEAST(3, 0, 0, 0)))
+
+// We must not do 'num + 0.5' or 'num - 0.5' because they can cause precision loss.
+static double round(double num)
+{
+ double integer = ceil(num);
+ if (num > 0)
+ return integer - num > 0.5 ? integer - 1.0 : integer;
+ return integer - num >= 0.5 ? integer - 1.0 : integer;
+}
+static float roundf(float num)
+{
+ float integer = ceilf(num);
+ if (num > 0)
+ return integer - num > 0.5f ? integer - 1.0f : integer;
+ return integer - num >= 0.5f ? integer - 1.0f : integer;
+}
+inline long long llround(double num) { return static_cast<long long>(round(num)); }
+inline long long llroundf(float num) { return static_cast<long long>(roundf(num)); }
+inline long lround(double num) { return static_cast<long>(round(num)); }
+inline long lroundf(float num) { return static_cast<long>(roundf(num)); }
+inline double trunc(double num) { return num > 0 ? floor(num) : ceil(num); }
+
+#endif
+
+#if COMPILER(GCC) && OS(QNX)
+// The stdlib on QNX doesn't contain long abs(long). See PR #104666.
+inline long long abs(long num) { return labs(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); }
+inline bool signbit(double num) { return _copysign(1.0, num) < 0; }
+
+inline double nextafter(double x, double y) { return _nextafter(x, y); }
+inline float nextafterf(float x, float y) { return x > y ? x - FLT_EPSILON : x + FLT_EPSILON; }
+
+inline double copysign(double x, double y) { return _copysign(x, y); }
+inline int isfinite(double x) { return _finite(x); }
+
+// MSVC's math.h does not currently supply log2 or log2f.
+inline double log2(double num)
+{
+ // This constant is roughly M_LN2, which is not provided by default on Windows.
+ return log(num) / 0.693147180559945309417232121458176568;
+}
+
+inline float log2f(float num)
+{
+ // This constant is roughly M_LN2, which is not provided by default on Windows.
+ return logf(num) / 0.693147180559945309417232121458176568f;
+}
+
+// Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values.
+inline double wtf_atan2(double x, double y)
+{
+ double posInf = std::numeric_limits<double>::infinity();
+ double negInf = -std::numeric_limits<double>::infinity();
+ double nan = std::numeric_limits<double>::quiet_NaN();
+
+ double result = nan;
+
+ if (x == posInf && y == posInf)
+ result = piOverFourDouble;
+ else if (x == posInf && y == negInf)
+ result = 3 * piOverFourDouble;
+ else if (x == negInf && y == posInf)
+ result = -piOverFourDouble;
+ else if (x == negInf && y == negInf)
+ result = -3 * piOverFourDouble;
+ else
+ result = ::atan2(x, y);
+
+ return result;
+}
+
+// Work around a bug in the Microsoft CRT, where fmod(x, +-infinity) yields NaN instead of x.
+inline double wtf_fmod(double x, double y) { return (!isinf(x) && isinf(y)) ? x : fmod(x, y); }
+
+// Work around a bug in the Microsoft CRT, where pow(NaN, 0) yields NaN instead of 1.
+inline double wtf_pow(double x, double y) { return y == 0 ? 1 : pow(x, y); }
+
+#define atan2(x, y) wtf_atan2(x, y)
+#define fmod(x, y) wtf_fmod(x, y)
+#define pow(x, y) wtf_pow(x, y)
+
+#endif // COMPILER(MSVC)
+
+inline double deg2rad(double d) { return d * piDouble / 180.0; }
+inline double rad2deg(double r) { return r * 180.0 / piDouble; }
+inline double deg2grad(double d) { return d * 400.0 / 360.0; }
+inline double grad2deg(double g) { return g * 360.0 / 400.0; }
+inline double turn2deg(double t) { return t * 360.0; }
+inline double deg2turn(double d) { return d / 360.0; }
+inline double rad2grad(double r) { return r * 200.0 / piDouble; }
+inline double grad2rad(double g) { return g * piDouble / 200.0; }
+
+inline float deg2rad(float d) { return d * piFloat / 180.0f; }
+inline float rad2deg(float r) { return r * 180.0f / piFloat; }
+inline float deg2grad(float d) { return d * 400.0f / 360.0f; }
+inline float grad2deg(float g) { return g * 360.0f / 400.0f; }
+inline float turn2deg(float t) { return t * 360.0f; }
+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; }
+
+// std::numeric_limits<T>::min() returns the smallest positive value for floating point types
+template<typename T> inline T defaultMinimumForClamp() { return std::numeric_limits<T>::min(); }
+template<> inline float defaultMinimumForClamp() { return -std::numeric_limits<float>::max(); }
+template<> inline double defaultMinimumForClamp() { return -std::numeric_limits<double>::max(); }
+template<typename T> inline T defaultMaximumForClamp() { return std::numeric_limits<T>::max(); }
+
+template<typename T> inline T clampTo(double value, T min = defaultMinimumForClamp<T>(), T max = defaultMaximumForClamp<T>())
+{
+ if (value >= static_cast<double>(max))
+ return max;
+ if (value <= static_cast<double>(min))
+ return min;
+ return static_cast<T>(value);
+}
+template<> inline long long int clampTo(double, long long int, long long int); // clampTo does not support long long ints.
+
+inline int clampToInteger(double value)
+{
+ return clampTo<int>(value);
+}
+
+inline float clampToFloat(double value)
+{
+ return clampTo<float>(value);
+}
+
+inline int clampToPositiveInteger(double value)
+{
+ return clampTo<int>(value, 0);
+}
+
+inline int clampToInteger(float value)
+{
+ return clampTo<int>(value);
+}
+
+inline int clampToInteger(unsigned x)
+{
+ const unsigned intMax = static_cast<unsigned>(std::numeric_limits<int>::max());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ return static_cast<int>(x);
+}
+
+inline bool isWithinIntRange(float x)
+{
+ return x > static_cast<float>(std::numeric_limits<int>::min()) && x < static_cast<float>(std::numeric_limits<int>::max());
+}
+
+#if !COMPILER(MSVC) && !COMPILER(RVCT) && !OS(SOLARIS)
+using std::isfinite;
+using std::isinf;
+using std::isnan;
+using std::signbit;
+#endif
+
+// decompose 'number' to its sign, exponent, and mantissa components.
+// The result is interpreted as:
+// (sign ? -1 : 1) * pow(2, exponent) * (mantissa / (1 << 52))
+inline void decomposeDouble(double number, bool& sign, int32_t& exponent, uint64_t& mantissa)
+{
+ ASSERT(isfinite(number));
+
+ sign = signbit(number);
+
+ uint64_t bits = WTF::bitwise_cast<uint64_t>(number);
+ exponent = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
+ mantissa = bits & 0xFFFFFFFFFFFFFull;
+
+ // Check for zero/denormal values; if so, adjust the exponent,
+ // if not insert the implicit, omitted leading 1 bit.
+ if (exponent == -0x3ff)
+ exponent = mantissa ? -0x3fe : 0;
+ else
+ mantissa |= 0x10000000000000ull;
+}
+
+// Calculate d % 2^{64}.
+inline void doubleToInteger(double d, unsigned long long& value)
+{
+ if (isnan(d) || isinf(d))
+ value = 0;
+ else {
+ // -2^{64} < fmodValue < 2^{64}.
+ double fmodValue = fmod(trunc(d), std::numeric_limits<unsigned long long>::max() + 1.0);
+ if (fmodValue >= 0) {
+ // 0 <= fmodValue < 2^{64}.
+ // 0 <= value < 2^{64}. This cast causes no loss.
+ value = static_cast<unsigned long long>(fmodValue);
+ } else {
+ // -2^{64} < fmodValue < 0.
+ // 0 < fmodValueInUnsignedLongLong < 2^{64}. This cast causes no loss.
+ unsigned long long fmodValueInUnsignedLongLong = static_cast<unsigned long long>(-fmodValue);
+ // -1 < (std::numeric_limits<unsigned long long>::max() - fmodValueInUnsignedLongLong) < 2^{64} - 1.
+ // 0 < value < 2^{64}.
+ value = std::numeric_limits<unsigned long long>::max() - fmodValueInUnsignedLongLong + 1;
+ }
+ }
+}
+
+#endif // #ifndef WTF_MathExtras_h
diff --git a/Source/JavaScriptCore/wtf/MessageQueue.h b/Source/JavaScriptCore/wtf/MessageQueue.h
new file mode 100644
index 000000000..dda852fe1
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MessageQueue.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 MessageQueue_h
+#define MessageQueue_h
+
+#include <limits>
+#include <wtf/Assertions.h>
+#include <wtf/Deque.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+ enum MessageQueueWaitResult {
+ MessageQueueTerminated, // Queue was destroyed while waiting for message.
+ MessageQueueTimeout, // Timeout was specified and it expired.
+ MessageQueueMessageReceived // A message was successfully received and returned.
+ };
+
+ // The queue takes ownership of messages and transfer it to the new owner
+ // when messages are fetched from the queue.
+ // Essentially, MessageQueue acts as a queue of OwnPtr<DataType>.
+ template<typename DataType>
+ class MessageQueue {
+ WTF_MAKE_NONCOPYABLE(MessageQueue);
+ public:
+ MessageQueue() : m_killed(false) { }
+ ~MessageQueue();
+
+ void append(PassOwnPtr<DataType>);
+ bool appendAndCheckEmpty(PassOwnPtr<DataType>);
+ void prepend(PassOwnPtr<DataType>);
+
+ PassOwnPtr<DataType> waitForMessage();
+ PassOwnPtr<DataType> tryGetMessage();
+ PassOwnPtr<DataType> tryGetMessageIgnoringKilled();
+ template<typename Predicate>
+ PassOwnPtr<DataType> waitForMessageFilteredWithTimeout(MessageQueueWaitResult&, Predicate&, double absoluteTime);
+
+ template<typename Predicate>
+ void removeIf(Predicate&);
+
+ void kill();
+ bool killed() const;
+
+ // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time.
+ bool isEmpty();
+
+ static double infiniteTime() { return std::numeric_limits<double>::max(); }
+
+ private:
+ static bool alwaysTruePredicate(DataType*) { return true; }
+
+ mutable Mutex m_mutex;
+ ThreadCondition m_condition;
+ Deque<DataType*> m_queue;
+ bool m_killed;
+ };
+
+ template<typename DataType>
+ MessageQueue<DataType>::~MessageQueue()
+ {
+ deleteAllValues(m_queue);
+ }
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::append(PassOwnPtr<DataType> message)
+ {
+ MutexLocker lock(m_mutex);
+ m_queue.append(message.leakPtr());
+ m_condition.signal();
+ }
+
+ // Returns true if the queue was empty before the item was added.
+ template<typename DataType>
+ inline bool MessageQueue<DataType>::appendAndCheckEmpty(PassOwnPtr<DataType> message)
+ {
+ MutexLocker lock(m_mutex);
+ bool wasEmpty = m_queue.isEmpty();
+ m_queue.append(message.leakPtr());
+ m_condition.signal();
+ return wasEmpty;
+ }
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::prepend(PassOwnPtr<DataType> message)
+ {
+ MutexLocker lock(m_mutex);
+ m_queue.prepend(message.leakPtr());
+ m_condition.signal();
+ }
+
+ template<typename DataType>
+ inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessage()
+ {
+ MessageQueueWaitResult exitReason;
+ OwnPtr<DataType> result = waitForMessageFilteredWithTimeout(exitReason, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime());
+ ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived);
+ return result.release();
+ }
+
+ template<typename DataType>
+ template<typename Predicate>
+ inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessageFilteredWithTimeout(MessageQueueWaitResult& result, Predicate& predicate, double absoluteTime)
+ {
+ MutexLocker lock(m_mutex);
+ bool timedOut = false;
+
+ DequeConstIterator<DataType*> found = m_queue.end();
+ while (!m_killed && !timedOut && (found = m_queue.findIf(predicate)) == m_queue.end())
+ timedOut = !m_condition.timedWait(m_mutex, absoluteTime);
+
+ ASSERT(!timedOut || absoluteTime != infiniteTime());
+
+ if (m_killed) {
+ result = MessageQueueTerminated;
+ return nullptr;
+ }
+
+ if (timedOut) {
+ result = MessageQueueTimeout;
+ return nullptr;
+ }
+
+ ASSERT(found != m_queue.end());
+ OwnPtr<DataType> message = adoptPtr(*found);
+ m_queue.remove(found);
+ result = MessageQueueMessageReceived;
+ return message.release();
+ }
+
+ template<typename DataType>
+ inline PassOwnPtr<DataType> MessageQueue<DataType>::tryGetMessage()
+ {
+ MutexLocker lock(m_mutex);
+ if (m_killed)
+ return nullptr;
+ if (m_queue.isEmpty())
+ return nullptr;
+
+ return adoptPtr(m_queue.takeFirst());
+ }
+
+ template<typename DataType>
+ inline PassOwnPtr<DataType> MessageQueue<DataType>::tryGetMessageIgnoringKilled()
+ {
+ MutexLocker lock(m_mutex);
+ if (m_queue.isEmpty())
+ return nullptr;
+
+ return adoptPtr(m_queue.takeFirst());
+ }
+
+ template<typename DataType>
+ template<typename Predicate>
+ inline void MessageQueue<DataType>::removeIf(Predicate& predicate)
+ {
+ MutexLocker lock(m_mutex);
+ DequeConstIterator<DataType*> found = m_queue.end();
+ while ((found = m_queue.findIf(predicate)) != m_queue.end()) {
+ DataType* message = *found;
+ m_queue.remove(found);
+ delete message;
+ }
+ }
+
+ template<typename DataType>
+ inline bool MessageQueue<DataType>::isEmpty()
+ {
+ MutexLocker lock(m_mutex);
+ if (m_killed)
+ return true;
+ return m_queue.isEmpty();
+ }
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::kill()
+ {
+ MutexLocker lock(m_mutex);
+ m_killed = true;
+ m_condition.broadcast();
+ }
+
+ template<typename DataType>
+ inline bool MessageQueue<DataType>::killed() const
+ {
+ MutexLocker lock(m_mutex);
+ return m_killed;
+ }
+} // namespace WTF
+
+using WTF::MessageQueue;
+// MessageQueueWaitResult enum and all its values.
+using WTF::MessageQueueWaitResult;
+using WTF::MessageQueueTerminated;
+using WTF::MessageQueueTimeout;
+using WTF::MessageQueueMessageReceived;
+
+#endif // MessageQueue_h
diff --git a/Source/JavaScriptCore/wtf/MetaAllocator.cpp b/Source/JavaScriptCore/wtf/MetaAllocator.cpp
new file mode 100644
index 000000000..92205a5d8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MetaAllocator.cpp
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "config.h"
+#include "MetaAllocator.h"
+
+#include <wtf/FastMalloc.h>
+
+namespace WTF {
+
+MetaAllocatorHandle::MetaAllocatorHandle(MetaAllocator* allocator, void* start, size_t sizeInBytes)
+ : m_allocator(allocator)
+ , m_start(start)
+ , m_sizeInBytes(sizeInBytes)
+{
+ ASSERT(allocator);
+ ASSERT(start);
+ ASSERT(sizeInBytes);
+}
+
+MetaAllocatorHandle::~MetaAllocatorHandle()
+{
+ if (!m_allocator)
+ return;
+ SpinLockHolder locker(&m_allocator->m_lock);
+ if (m_sizeInBytes) {
+ m_allocator->decrementPageOccupancy(m_start, m_sizeInBytes);
+ m_allocator->addFreeSpaceFromReleasedHandle(m_start, m_sizeInBytes);
+ }
+}
+
+void MetaAllocatorHandle::shrink(size_t newSizeInBytes)
+{
+ ASSERT(newSizeInBytes <= m_sizeInBytes);
+
+ if (!m_allocator) {
+ m_sizeInBytes = newSizeInBytes;
+ return;
+ }
+
+ SpinLockHolder locker(&m_allocator->m_lock);
+
+ newSizeInBytes = m_allocator->roundUp(newSizeInBytes);
+
+ ASSERT(newSizeInBytes <= m_sizeInBytes);
+
+ if (newSizeInBytes == m_sizeInBytes)
+ return;
+
+ uintptr_t freeStart = reinterpret_cast<uintptr_t>(m_start) + newSizeInBytes;
+ size_t freeSize = m_sizeInBytes - newSizeInBytes;
+ uintptr_t freeEnd = freeStart + freeSize;
+
+ uintptr_t firstCompletelyFreePage = (freeStart + m_allocator->m_pageSize - 1) & ~(m_allocator->m_pageSize - 1);
+ if (firstCompletelyFreePage < freeEnd)
+ m_allocator->decrementPageOccupancy(reinterpret_cast<void*>(firstCompletelyFreePage), freeSize - (firstCompletelyFreePage - freeStart));
+
+ m_allocator->addFreeSpaceFromReleasedHandle(reinterpret_cast<void*>(freeStart), freeSize);
+
+ m_sizeInBytes = newSizeInBytes;
+}
+
+MetaAllocator::MetaAllocator(size_t allocationGranule)
+ : m_allocationGranule(allocationGranule)
+ , m_pageSize(pageSize())
+ , m_bytesAllocated(0)
+ , m_bytesReserved(0)
+ , m_bytesCommitted(0)
+#ifndef NDEBUG
+ , m_mallocBalance(0)
+#endif
+#if ENABLE(META_ALLOCATOR_PROFILE)
+ , m_numAllocations(0)
+ , m_numFrees(0)
+#endif
+{
+ m_lock.Init();
+
+ for (m_logPageSize = 0; m_logPageSize < 32; ++m_logPageSize) {
+ if (static_cast<size_t>(1) << m_logPageSize == m_pageSize)
+ break;
+ }
+
+ ASSERT(static_cast<size_t>(1) << m_logPageSize == m_pageSize);
+
+ for (m_logAllocationGranule = 0; m_logAllocationGranule < 32; ++m_logAllocationGranule) {
+ if (static_cast<size_t>(1) << m_logAllocationGranule == m_allocationGranule)
+ break;
+ }
+
+ ASSERT(static_cast<size_t>(1) << m_logAllocationGranule == m_allocationGranule);
+}
+
+PassRefPtr<MetaAllocatorHandle> MetaAllocator::allocate(size_t sizeInBytes)
+{
+ SpinLockHolder locker(&m_lock);
+
+ if (!sizeInBytes)
+ return 0;
+
+ sizeInBytes = roundUp(sizeInBytes);
+
+ void* start = findAndRemoveFreeSpace(sizeInBytes);
+ if (!start) {
+ size_t requestedNumberOfPages = (sizeInBytes + m_pageSize - 1) >> m_logPageSize;
+ size_t numberOfPages = requestedNumberOfPages;
+
+ start = allocateNewSpace(numberOfPages);
+ if (!start)
+ return 0;
+
+ ASSERT(numberOfPages >= requestedNumberOfPages);
+
+ size_t roundedUpSize = numberOfPages << m_logPageSize;
+
+ ASSERT(roundedUpSize >= sizeInBytes);
+
+ m_bytesReserved += roundedUpSize;
+
+ if (roundedUpSize > sizeInBytes) {
+ void* freeSpaceStart = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start) + sizeInBytes);
+ size_t freeSpaceSize = roundedUpSize - sizeInBytes;
+ addFreeSpace(freeSpaceStart, freeSpaceSize);
+ }
+ }
+ incrementPageOccupancy(start, sizeInBytes);
+ m_bytesAllocated += sizeInBytes;
+#if ENABLE(META_ALLOCATOR_PROFILE)
+ m_numAllocations++;
+#endif
+
+ MetaAllocatorHandle* handle = new MetaAllocatorHandle(this, start, sizeInBytes);
+ // FIXME: Implement a verifier scheme that groks MetaAllocatorHandles
+ handle->deprecatedTurnOffVerifier();
+
+ return adoptRef(handle);
+}
+
+MetaAllocator::Statistics MetaAllocator::currentStatistics()
+{
+ SpinLockHolder locker(&m_lock);
+ Statistics result;
+ result.bytesAllocated = m_bytesAllocated;
+ result.bytesReserved = m_bytesReserved;
+ result.bytesCommitted = m_bytesCommitted;
+ return result;
+}
+
+void* MetaAllocator::findAndRemoveFreeSpace(size_t sizeInBytes)
+{
+ FreeSpaceNode* node = m_freeSpaceSizeMap.findLeastGreaterThanOrEqual(sizeInBytes);
+
+ if (!node)
+ return 0;
+
+ ASSERT(node->m_key >= sizeInBytes);
+
+ m_freeSpaceSizeMap.remove(node);
+
+ void* result;
+
+ if (node->m_key == sizeInBytes) {
+ // Easy case: perfect fit, so just remove the node entirely.
+ result = node->m_value;
+
+ m_freeSpaceStartAddressMap.remove(node->m_value);
+ m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key));
+ freeFreeSpaceNode(node);
+ } else {
+ // Try to be a good citizen and ensure that the returned chunk of memory
+ // straddles as few pages as possible, but only insofar as doing so will
+ // not increase fragmentation. The intuition is that minimizing
+ // fragmentation is a strictly higher priority than minimizing the number
+ // of committed pages, since in the long run, smaller fragmentation means
+ // fewer committed pages and fewer failures in general.
+
+ uintptr_t firstPage = reinterpret_cast<uintptr_t>(node->m_value) >> m_logPageSize;
+ uintptr_t lastPage = (reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - 1) >> m_logPageSize;
+
+ uintptr_t lastPageForLeftAllocation = (reinterpret_cast<uintptr_t>(node->m_value) + sizeInBytes - 1) >> m_logPageSize;
+ uintptr_t firstPageForRightAllocation = (reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - sizeInBytes) >> m_logPageSize;
+
+ if (lastPageForLeftAllocation - firstPage + 1 <= lastPage - firstPageForRightAllocation + 1) {
+ // Allocate in the left side of the returned chunk, and slide the node to the right.
+ result = node->m_value;
+
+ m_freeSpaceStartAddressMap.remove(node->m_value);
+
+ node->m_key -= sizeInBytes;
+ node->m_value = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + sizeInBytes);
+
+ m_freeSpaceSizeMap.insert(node);
+ m_freeSpaceStartAddressMap.add(node->m_value, node);
+ } else {
+ // Allocate in the right size of the returned chunk, and slide the node to the left;
+
+ result = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key - sizeInBytes);
+
+ m_freeSpaceEndAddressMap.remove(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(node->m_value) + node->m_key));
+
+ node->m_key -= sizeInBytes;
+
+ m_freeSpaceSizeMap.insert(node);
+ m_freeSpaceEndAddressMap.add(result, node);
+ }
+ }
+
+ return result;
+}
+
+void MetaAllocator::addFreeSpaceFromReleasedHandle(void* start, size_t sizeInBytes)
+{
+#if ENABLE(META_ALLOCATOR_PROFILE)
+ m_numFrees++;
+#endif
+ m_bytesAllocated -= sizeInBytes;
+ addFreeSpace(start, sizeInBytes);
+}
+
+void MetaAllocator::addFreshFreeSpace(void* start, size_t sizeInBytes)
+{
+ SpinLockHolder locker(&m_lock);
+ m_bytesReserved += sizeInBytes;
+ addFreeSpace(start, sizeInBytes);
+}
+
+size_t MetaAllocator::debugFreeSpaceSize()
+{
+#ifndef NDEBUG
+ SpinLockHolder locker(&m_lock);
+ size_t result = 0;
+ for (FreeSpaceNode* node = m_freeSpaceSizeMap.first(); node; node = node->successor())
+ result += node->m_key;
+ return result;
+#else
+ CRASH();
+ return 0;
+#endif
+}
+
+void MetaAllocator::addFreeSpace(void* start, size_t sizeInBytes)
+{
+ void* end = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start) + sizeInBytes);
+
+ HashMap<void*, FreeSpaceNode*>::iterator leftNeighbor = m_freeSpaceEndAddressMap.find(start);
+ HashMap<void*, FreeSpaceNode*>::iterator rightNeighbor = m_freeSpaceStartAddressMap.find(end);
+
+ if (leftNeighbor != m_freeSpaceEndAddressMap.end()) {
+ // We have something we can coalesce with on the left. Remove it from the tree, and
+ // remove its end from the end address map.
+
+ ASSERT(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftNeighbor->second->m_value) + leftNeighbor->second->m_key) == leftNeighbor->first);
+
+ FreeSpaceNode* leftNode = leftNeighbor->second;
+
+ void* leftStart = leftNode->m_value;
+ size_t leftSize = leftNode->m_key;
+ void* leftEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftStart) + leftSize);
+
+ ASSERT(leftEnd == start);
+
+ m_freeSpaceSizeMap.remove(leftNode);
+ m_freeSpaceEndAddressMap.remove(leftEnd);
+
+ // Now check if there is also something to coalesce with on the right.
+ if (rightNeighbor != m_freeSpaceStartAddressMap.end()) {
+ // Freeing something in the middle of free blocks. Coalesce both left and
+ // right, whilst removing the right neighbor from the maps.
+
+ ASSERT(rightNeighbor->second->m_value == rightNeighbor->first);
+
+ FreeSpaceNode* rightNode = rightNeighbor->second;
+ void* rightStart = rightNeighbor->first;
+ size_t rightSize = rightNode->m_key;
+ void* rightEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(rightStart) + rightSize);
+
+ ASSERT(rightStart == end);
+ ASSERT(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(leftStart) + leftSize + sizeInBytes + rightSize) == rightEnd);
+
+ m_freeSpaceSizeMap.remove(rightNode);
+ m_freeSpaceStartAddressMap.remove(rightStart);
+ m_freeSpaceEndAddressMap.remove(rightEnd);
+
+ freeFreeSpaceNode(rightNode);
+
+ leftNode->m_key += sizeInBytes + rightSize;
+
+ m_freeSpaceSizeMap.insert(leftNode);
+ m_freeSpaceEndAddressMap.add(rightEnd, leftNode);
+ } else {
+ leftNode->m_key += sizeInBytes;
+
+ m_freeSpaceSizeMap.insert(leftNode);
+ m_freeSpaceEndAddressMap.add(end, leftNode);
+ }
+ } else {
+ // Cannot coalesce with left; try to see if we can coalesce with right.
+
+ if (rightNeighbor != m_freeSpaceStartAddressMap.end()) {
+ FreeSpaceNode* rightNode = rightNeighbor->second;
+ void* rightStart = rightNeighbor->first;
+ size_t rightSize = rightNode->m_key;
+ void* rightEnd = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(rightStart) + rightSize);
+
+ ASSERT(rightStart == end);
+ ASSERT_UNUSED(rightEnd, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start) + sizeInBytes + rightSize) == rightEnd);
+
+ m_freeSpaceSizeMap.remove(rightNode);
+ m_freeSpaceStartAddressMap.remove(rightStart);
+
+ rightNode->m_key += sizeInBytes;
+ rightNode->m_value = start;
+
+ m_freeSpaceSizeMap.insert(rightNode);
+ m_freeSpaceStartAddressMap.add(start, rightNode);
+ } else {
+ // Nothing to coalesce with, so create a new free space node and add it.
+
+ FreeSpaceNode* node = allocFreeSpaceNode();
+
+ node->m_key = sizeInBytes;
+ node->m_value = start;
+
+ m_freeSpaceSizeMap.insert(node);
+ m_freeSpaceStartAddressMap.add(start, node);
+ m_freeSpaceEndAddressMap.add(end, node);
+ }
+ }
+}
+
+void MetaAllocator::incrementPageOccupancy(void* address, size_t sizeInBytes)
+{
+ uintptr_t firstPage = reinterpret_cast<uintptr_t>(address) >> m_logPageSize;
+ uintptr_t lastPage = (reinterpret_cast<uintptr_t>(address) + sizeInBytes - 1) >> m_logPageSize;
+
+ for (uintptr_t page = firstPage; page <= lastPage; ++page) {
+ HashMap<uintptr_t, size_t>::iterator iter = m_pageOccupancyMap.find(page);
+ if (iter == m_pageOccupancyMap.end()) {
+ m_pageOccupancyMap.add(page, 1);
+ m_bytesCommitted += m_pageSize;
+ notifyNeedPage(reinterpret_cast<void*>(page << m_logPageSize));
+ } else
+ iter->second++;
+ }
+}
+
+void MetaAllocator::decrementPageOccupancy(void* address, size_t sizeInBytes)
+{
+ uintptr_t firstPage = reinterpret_cast<uintptr_t>(address) >> m_logPageSize;
+ uintptr_t lastPage = (reinterpret_cast<uintptr_t>(address) + sizeInBytes - 1) >> m_logPageSize;
+
+ for (uintptr_t page = firstPage; page <= lastPage; ++page) {
+ HashMap<uintptr_t, size_t>::iterator iter = m_pageOccupancyMap.find(page);
+ ASSERT(iter != m_pageOccupancyMap.end());
+ if (!--(iter->second)) {
+ m_pageOccupancyMap.remove(iter);
+ m_bytesCommitted -= m_pageSize;
+ notifyPageIsFree(reinterpret_cast<void*>(page << m_logPageSize));
+ }
+ }
+}
+
+size_t MetaAllocator::roundUp(size_t sizeInBytes)
+{
+ if (std::numeric_limits<size_t>::max() - m_allocationGranule <= sizeInBytes)
+ CRASH();
+ return (sizeInBytes + m_allocationGranule - 1) & ~(m_allocationGranule - 1);
+}
+
+MetaAllocator::FreeSpaceNode* MetaAllocator::allocFreeSpaceNode()
+{
+#ifndef NDEBUG
+ m_mallocBalance++;
+#endif
+ return new (NotNull, fastMalloc(sizeof(FreeSpaceNode))) FreeSpaceNode(0, 0);
+}
+
+void MetaAllocator::freeFreeSpaceNode(FreeSpaceNode* node)
+{
+#ifndef NDEBUG
+ m_mallocBalance--;
+#endif
+ fastFree(node);
+}
+
+#if ENABLE(META_ALLOCATOR_PROFILE)
+void MetaAllocator::dumpProfile()
+{
+ printf("num allocations = %u, num frees = %u\n", m_numAllocations, m_numFrees);
+}
+#endif
+
+} // namespace WTF
+
+
diff --git a/Source/JavaScriptCore/wtf/MetaAllocator.h b/Source/JavaScriptCore/wtf/MetaAllocator.h
new file mode 100644
index 000000000..cf971b720
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MetaAllocator.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 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 WTF_MetaAllocator_h
+#define WTF_MetaAllocator_h
+
+#include "Assertions.h"
+#include "HashMap.h"
+#include "MetaAllocatorHandle.h"
+#include "Noncopyable.h"
+#include "PageBlock.h"
+#include "RedBlackTree.h"
+#include "RefCounted.h"
+#include "RefPtr.h"
+#include "TCSpinLock.h"
+
+namespace WTF {
+
+#define ENABLE_META_ALLOCATOR_PROFILE 0
+
+class MetaAllocator {
+ WTF_MAKE_NONCOPYABLE(MetaAllocator);
+public:
+
+ MetaAllocator(size_t allocationGranule);
+
+ virtual ~MetaAllocator();
+
+ PassRefPtr<MetaAllocatorHandle> allocate(size_t sizeInBytes);
+
+ // Non-atomic methods for getting allocator statistics.
+ size_t bytesAllocated() { return m_bytesAllocated; }
+ size_t bytesReserved() { return m_bytesReserved; }
+ size_t bytesCommitted() { return m_bytesCommitted; }
+
+ // Atomic method for getting allocator statistics.
+ struct Statistics {
+ size_t bytesAllocated;
+ size_t bytesReserved;
+ size_t bytesCommitted;
+ };
+ Statistics currentStatistics();
+
+ // Add more free space to the allocator. Call this directly from
+ // the constructor if you wish to operate the allocator within a
+ // fixed pool.
+ void addFreshFreeSpace(void* start, size_t sizeInBytes);
+
+ // This is meant only for implementing tests. Never call this in release
+ // builds.
+ size_t debugFreeSpaceSize();
+
+#if ENABLE(META_ALLOCATOR_PROFILE)
+ void dumpProfile();
+#else
+ void dumpProfile() { }
+#endif
+
+protected:
+
+ // Allocate new virtual space, but don't commit. This may return more
+ // pages than we asked, in which case numPages is changed.
+ virtual void* allocateNewSpace(size_t& numPages) = 0;
+
+ // Commit a page.
+ virtual void notifyNeedPage(void* page) = 0;
+
+ // Uncommit a page.
+ virtual void notifyPageIsFree(void* page) = 0;
+
+ // NOTE: none of the above methods are called during allocator
+ // destruction, in part because a MetaAllocator cannot die so long
+ // as there are Handles that refer to it.
+
+private:
+
+ friend class MetaAllocatorHandle;
+
+ typedef RedBlackTree<size_t, void*> Tree;
+ typedef Tree::Node FreeSpaceNode;
+
+ // Remove free space from the allocator. This is effectively
+ // the allocate() function, except that it does not mark the
+ // returned space as being in-use.
+ void* findAndRemoveFreeSpace(size_t sizeInBytes);
+
+ // This is called when memory from an allocation is freed.
+ void addFreeSpaceFromReleasedHandle(void* start, size_t sizeInBytes);
+
+ // This is the low-level implementation of adding free space; it
+ // is called from both addFreeSpaceFromReleasedHandle and from
+ // addFreshFreeSpace.
+ void addFreeSpace(void* start, size_t sizeInBytes);
+
+ // Management of used space.
+
+ void incrementPageOccupancy(void* address, size_t sizeInBytes);
+ void decrementPageOccupancy(void* address, size_t sizeInBytes);
+
+ // Utilities.
+
+ size_t roundUp(size_t sizeInBytes);
+
+ FreeSpaceNode* allocFreeSpaceNode();
+ void freeFreeSpaceNode(FreeSpaceNode*);
+
+ size_t m_allocationGranule;
+ unsigned m_logAllocationGranule;
+ size_t m_pageSize;
+ unsigned m_logPageSize;
+
+ Tree m_freeSpaceSizeMap;
+ HashMap<void*, FreeSpaceNode*> m_freeSpaceStartAddressMap;
+ HashMap<void*, FreeSpaceNode*> m_freeSpaceEndAddressMap;
+ HashMap<uintptr_t, size_t> m_pageOccupancyMap;
+
+ size_t m_bytesAllocated;
+ size_t m_bytesReserved;
+ size_t m_bytesCommitted;
+
+ SpinLock m_lock;
+
+#ifndef NDEBUG
+ size_t m_mallocBalance;
+#endif
+
+#if ENABLE(META_ALLOCATOR_PROFILE)
+ unsigned m_numAllocations;
+ unsigned m_numFrees;
+#endif
+};
+
+inline MetaAllocator::~MetaAllocator()
+{
+ for (FreeSpaceNode* node = m_freeSpaceSizeMap.first(); node;) {
+ FreeSpaceNode* next = node->successor();
+ m_freeSpaceSizeMap.remove(node);
+ freeFreeSpaceNode(node);
+ node = next;
+ }
+#ifndef NDEBUG
+ ASSERT(!m_mallocBalance);
+#endif
+}
+
+} // namespace WTF
+
+#endif // WTF_MetaAllocator_h
+
diff --git a/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h b/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h
new file mode 100644
index 000000000..5a32081d4
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/MetaAllocatorHandle.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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 WTF_MetaAllocatorHandle_h
+#define WTF_MetaAllocatorHandle_h
+
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WTF {
+
+class MetaAllocator;
+
+class MetaAllocatorHandle : public RefCounted<MetaAllocatorHandle> {
+private:
+ MetaAllocatorHandle(MetaAllocator*, void* start, size_t sizeInBytes);
+
+ MetaAllocatorHandle(void* start, size_t sizeInBytes)
+ : m_allocator(0)
+ , m_start(start)
+ , m_sizeInBytes(sizeInBytes)
+ {
+ ASSERT(start);
+ }
+
+public:
+ ~MetaAllocatorHandle();
+
+ static PassRefPtr<MetaAllocatorHandle> createSelfManagedHandle(void* start, size_t sizeInBytes)
+ {
+ return adoptRef(new MetaAllocatorHandle(start, sizeInBytes));
+ }
+
+ void* start()
+ {
+ return m_start;
+ }
+
+ void* end()
+ {
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(m_start) + m_sizeInBytes);
+ }
+
+ size_t sizeInBytes()
+ {
+ return m_sizeInBytes;
+ }
+
+ void shrink(size_t newSizeInBytes);
+
+ bool isManaged()
+ {
+ return !!m_allocator;
+ }
+
+ MetaAllocator* allocator()
+ {
+ ASSERT(m_allocator);
+ return m_allocator;
+ }
+
+private:
+ friend class MetaAllocator;
+
+ MetaAllocator* m_allocator;
+ void* m_start;
+ size_t m_sizeInBytes;
+};
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/NonCopyingSort.h b/Source/JavaScriptCore/wtf/NonCopyingSort.h
new file mode 100644
index 000000000..fd611bde7
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/Noncopyable.h b/Source/JavaScriptCore/wtf/Noncopyable.h
new file mode 100644
index 000000000..9f93f173b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Noncopyable.h
@@ -0,0 +1,42 @@
+/*
+ * 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
+ * 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_Noncopyable_h
+#define WTF_Noncopyable_h
+
+#include "Compiler.h"
+
+#if COMPILER_SUPPORTS(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
+
+#endif // WTF_Noncopyable_h
diff --git a/Source/JavaScriptCore/wtf/NotFound.h b/Source/JavaScriptCore/wtf/NotFound.h
new file mode 100644
index 000000000..4263bceca
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/NotFound.h
@@ -0,0 +1,37 @@
+/*
+ * 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 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 NotFound_h
+#define NotFound_h
+
+namespace WTF {
+
+ const size_t notFound = static_cast<size_t>(-1);
+
+} // namespace WTF
+
+using WTF::notFound;
+
+#endif // NotFound_h
diff --git a/Source/JavaScriptCore/wtf/NullPtr.cpp b/Source/JavaScriptCore/wtf/NullPtr.cpp
new file mode 100644
index 000000000..fb75cf6d5
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/NullPtr.cpp
@@ -0,0 +1,34 @@
+/*
+
+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 "config.h"
+#include "NullPtr.h"
+
+#if !COMPILER_SUPPORTS(CXX_NULLPTR)
+
+std::nullptr_t nullptr;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/NullPtr.h b/Source/JavaScriptCore/wtf/NullPtr.h
new file mode 100644
index 000000000..b65f8fab5
--- /dev/null
+++ b/Source/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.
+
+#if COMPILER_SUPPORTS(CXX_NULLPTR)
+
+#include <cstddef>
+
+#else
+
+namespace std {
+ class nullptr_t { };
+}
+
+extern std::nullptr_t nullptr;
+
+#endif
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/OSAllocator.h b/Source/JavaScriptCore/wtf/OSAllocator.h
new file mode 100644
index 000000000..bf9f04968
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OSAllocator.h
@@ -0,0 +1,100 @@
+/*
+ * 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 OSAllocator_h
+#define OSAllocator_h
+
+#include <wtf/UnusedParam.h>
+#include <wtf/VMTags.h>
+#include <wtf/VMTags.h>
+
+namespace WTF {
+
+class OSAllocator {
+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,
+ };
+
+ // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
+ // releaseDecommitted should be called on a region of VM allocated by a single reservation,
+ // the memory must all currently be in a decommitted state.
+ static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false);
+ static void releaseDecommitted(void*, size_t);
+
+ // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
+ // never be accessed, since the OS may not have attached physical memory for these regions).
+ // Clients should only call commit on uncommitted regions and decommit on committed regions.
+ static void commit(void*, size_t, bool writable, bool executable);
+ static void decommit(void*, size_t);
+
+ // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
+ // decommitAndRelease should be called on a region of VM allocated by a single reservation,
+ // the memory must all currently be in a committed state.
+ static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false);
+ static void decommitAndRelease(void* base, size_t size);
+
+ // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
+ // committing/decommitting the entire region additional parameters allow a subregion to be
+ // specified.
+ static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
+ static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
+};
+
+inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
+{
+ void* base = reserveUncommitted(reserveSize, usage, writable, executable);
+ commit(base, commitSize, writable, executable);
+ return base;
+}
+
+inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
+{
+ ASSERT(decommitBase >= releaseBase && (static_cast<char*>(decommitBase) + decommitSize) <= (static_cast<char*>(releaseBase) + releaseSize));
+#if OS(WINCE)
+ // On most platforms we can actually skip this final decommit; releasing the VM will
+ // implicitly decommit any physical memory in the region. This is not true on WINCE.
+ decommit(decommitBase, decommitSize);
+#else
+ UNUSED_PARAM(decommitBase);
+ UNUSED_PARAM(decommitSize);
+#endif
+ releaseDecommitted(releaseBase, releaseSize);
+}
+
+inline void OSAllocator::decommitAndRelease(void* base, size_t size)
+{
+ decommitAndRelease(base, size, base, size);
+}
+
+} // namespace WTF
+
+using WTF::OSAllocator;
+
+#endif // OSAllocator_h
diff --git a/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp b/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp
new file mode 100644
index 000000000..b264f685a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 "config.h"
+#include "OSAllocator.h"
+
+#include "PageAllocation.h"
+#include <errno.h>
+#include <sys/mman.h>
+#include <wtf/Assertions.h>
+#include <wtf/UnusedParam.h>
+
+namespace WTF {
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ void* result = reserveAndCommit(bytes, usage, writable, executable, includesGuardPages);
+#if HAVE(MADV_FREE_REUSE)
+ // To support the "reserve then commit" model, we have to initially decommit.
+ while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#endif
+ return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ // All POSIX reservations start out logically committed.
+ int protection = PROT_READ;
+ if (writable)
+ protection |= PROT_WRITE;
+ if (executable)
+ protection |= PROT_EXEC;
+
+ int flags = MAP_PRIVATE | MAP_ANON;
+#if PLATFORM(IOS)
+ if (executable)
+ flags |= MAP_JIT;
+#endif
+
+#if OS(LINUX)
+ // Linux distros usually do not allow overcommit by default, so
+ // JSC's strategy of mmaping a large amount of memory upfront
+ // won't work very well on some systems. Fortunately there's a
+ // flag we can pass to mmap to disable the overcommit check for
+ // this particular call, so we can get away with it as long as the
+ // overcommit flag value in /proc/sys/vm/overcommit_memory is 0
+ // ('heuristic') and not 2 (always check). 0 is the usual default
+ // value, so this should work well in general.
+ flags |= MAP_NORESERVE;
+#endif
+
+#if OS(DARWIN)
+ int fd = usage;
+#else
+ int fd = -1;
+#endif
+
+ void* result = 0;
+#if (OS(DARWIN) && CPU(X86_64))
+ if (executable) {
+ ASSERT(includesGuardPages);
+ // Cook up an address to allocate at, using the following recipe:
+ // 17 bits of zero, stay in userspace kids.
+ // 26 bits of randomness for ASLR.
+ // 21 bits of zero, at least stay aligned within one level of the pagetables.
+ //
+ // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
+ // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
+ // 2^24, which should put up somewhere in the middle of userspace (in the address range
+ // 0x200000000000 .. 0x5fffffffffff).
+ intptr_t randomLocation = 0;
+ randomLocation = arc4random() & ((1 << 25) - 1);
+ randomLocation += (1 << 24);
+ randomLocation <<= 21;
+ result = reinterpret_cast<void*>(randomLocation);
+ }
+#endif
+
+ result = mmap(result, bytes, protection, flags, fd, 0);
+ if (result == MAP_FAILED) {
+ #if ENABLE(INTERPRETER)
+ if (executable)
+ result = 0;
+ else
+ #endif
+ CRASH();
+ }
+ if (result && includesGuardPages) {
+ // We use mmap to remap the guardpages rather than using mprotect as
+ // mprotect results in multiple references to the code region. This
+ // breaks the madvise based mechanism we use to return physical memory
+ // to the OS.
+ mmap(result, pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
+ mmap(static_cast<char*>(result) + bytes - pageSize(), pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
+ }
+ return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool, bool)
+{
+#if HAVE(MADV_FREE_REUSE)
+ while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
+#else
+ // Non-MADV_FREE_REUSE reservations automatically commit on demand.
+ UNUSED_PARAM(address);
+ UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+#if HAVE(MADV_FREE_REUSE)
+ while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#elif HAVE(MADV_FREE)
+ while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
+#elif HAVE(MADV_DONTNEED)
+ while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
+#else
+ UNUSED_PARAM(address);
+ UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ int result = munmap(address, bytes);
+ if (result == -1)
+ CRASH();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/OSAllocatorWin.cpp b/Source/JavaScriptCore/wtf/OSAllocatorWin.cpp
new file mode 100644
index 000000000..7f5d9b890
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OSAllocatorWin.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. 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 "config.h"
+#include "OSAllocator.h"
+
+#include "windows.h"
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+static inline DWORD protection(bool writable, bool executable)
+{
+ return executable ?
+ (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
+ (writable ? PAGE_READWRITE : PAGE_READONLY);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable, bool)
+{
+ void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable, bool)
+{
+ void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+ void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
+ if (!result)
+ CRASH();
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+ bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
+ if (!result)
+ CRASH();
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
+ // dwSize must be 0 if dwFreeType is MEM_RELEASE.
+ bool result = VirtualFree(address, 0, MEM_RELEASE);
+ if (!result)
+ CRASH();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/OSRandomSource.cpp b/Source/JavaScriptCore/wtf/OSRandomSource.cpp
new file mode 100644
index 000000000..0c1416a2f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OSRandomSource.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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 GOOGLE, 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 "OSRandomSource.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if OS(UNIX)
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#if OS(WINDOWS)
+#include <windows.h>
+#include <wincrypt.h> // windows.h must be included before wincrypt.h.
+#endif
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+void cryptographicallyRandomValuesFromOS(unsigned char* buffer, size_t length)
+{
+#if OS(UNIX)
+ int fd = open("/dev/urandom", O_RDONLY, 0);
+ if (fd < 0)
+ CRASH(); // We need /dev/urandom for this API to work...
+
+ if (read(fd, buffer, length) != static_cast<ssize_t>(length))
+ CRASH();
+
+ close(fd);
+#elif OS(WINDOWS)
+ HCRYPTPROV hCryptProv = 0;
+ if (!CryptAcquireContext(&hCryptProv, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ CRASH();
+ if (!CryptGenRandom(hCryptProv, length, buffer))
+ CRASH();
+ CryptReleaseContext(hCryptProv, 0);
+#else
+ #error "This configuration doesn't have a strong source of randomness."
+ // WARNING: When adding new sources of OS randomness, the randomness must
+ // be of cryptographic quality!
+#endif
+}
+#endif
+
+}
diff --git a/Source/JavaScriptCore/wtf/OSRandomSource.h b/Source/JavaScriptCore/wtf/OSRandomSource.h
new file mode 100644
index 000000000..214a95472
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OSRandomSource.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 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 GOOGLE, 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_OSRandomSource_h
+#define WTF_OSRandomSource_h
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+// This function attempts to fill buffer with randomness from the operating
+// system. If insufficient randomness is available, the buffer will be
+// partially filled. Rather than calling this function directly, consider
+// calling cryptographicallyRandomNumber or cryptographicallyRandomValues.
+void cryptographicallyRandomValuesFromOS(unsigned char* buffer, size_t length);
+#endif
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/OwnArrayPtr.h b/Source/JavaScriptCore/wtf/OwnArrayPtr.h
new file mode 100644
index 000000000..0fc8e71b3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OwnArrayPtr.h
@@ -0,0 +1,157 @@
+/*
+ * 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
+ * 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_OwnArrayPtr_h
+#define WTF_OwnArrayPtr_h
+
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "NullPtr.h"
+#include "PassOwnArrayPtr.h"
+#include <algorithm>
+
+namespace WTF {
+
+template<typename T> class PassOwnArrayPtr;
+template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*);
+
+template <typename T> class OwnArrayPtr {
+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>&);
+
+ ~OwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); }
+
+ PtrType get() const { return m_ptr; }
+
+ void clear();
+ PassOwnArrayPtr<T> release();
+ PtrType leakPtr() WARN_UNUSED_RETURN;
+
+ T& operator*() const { ASSERT(m_ptr); return *m_ptr; }
+ PtrType operator->() const { ASSERT(m_ptr); return m_ptr; }
+
+ T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef T* OwnArrayPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; }
+
+ 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:
+ 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;
+}
+
+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
+
+using WTF::OwnArrayPtr;
+
+#endif // WTF_OwnArrayPtr_h
diff --git a/Source/JavaScriptCore/wtf/OwnFastMallocPtr.h b/Source/JavaScriptCore/wtf/OwnFastMallocPtr.h
new file mode 100644
index 000000000..183bfec8f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OwnFastMallocPtr.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006, 2007 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 OwnFastMallocPtr_h
+#define OwnFastMallocPtr_h
+
+#include "FastMalloc.h"
+#include <wtf/Noncopyable.h>
+
+namespace WTF {
+
+ template<class T> class OwnFastMallocPtr {
+ WTF_MAKE_NONCOPYABLE(OwnFastMallocPtr);
+ public:
+ explicit OwnFastMallocPtr(T* ptr) : m_ptr(ptr)
+ {
+ }
+
+ ~OwnFastMallocPtr()
+ {
+ fastFree(const_cast<void*>(static_cast<const void*>(const_cast<const T*>(m_ptr))));
+ }
+
+ T* get() const { return m_ptr; }
+ T* release() { T* ptr = m_ptr; m_ptr = 0; return ptr; }
+
+ private:
+ T* m_ptr;
+ };
+
+} // namespace WTF
+
+using WTF::OwnFastMallocPtr;
+
+#endif // OwnFastMallocPtr_h
diff --git a/Source/JavaScriptCore/wtf/OwnPtr.h b/Source/JavaScriptCore/wtf/OwnPtr.h
new file mode 100644
index 000000000..097967964
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OwnPtr.h
@@ -0,0 +1,169 @@
+/*
+ * 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
+ * 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_OwnPtr_h
+#define WTF_OwnPtr_h
+
+#include "Assertions.h"
+#include "NullPtr.h"
+#include "OwnPtrCommon.h"
+#include "TypeTraits.h"
+#include <algorithm>
+#include <memory>
+
+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> PassOwnPtr<T> adoptPtr(T*);
+
+ template<typename T> class OwnPtr {
+ public:
+ typedef typename RemovePointer<T>::Type ValueType;
+ typedef ValueType* PtrType;
+
+ OwnPtr() : m_ptr(0) { }
+ OwnPtr(std::nullptr_t) : m_ptr(0) { }
+
+ // See comment in PassOwnPtr.h for why this takes a const reference.
+ 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
+ // should optimize away the constructor when generating code.
+ OwnPtr(const OwnPtr<ValueType>&);
+
+ ~OwnPtr() { deleteOwnedPtr(m_ptr); }
+
+ PtrType get() const { return m_ptr; }
+
+ 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; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef PtrType OwnPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &OwnPtr::m_ptr : 0; }
+
+ OwnPtr& operator=(const PassOwnPtr<T>&);
+ 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); }
+
+ private:
+ OwnPtr& operator=(const OwnPtr<T>&);
+
+ // We should never have two OwnPtrs for the same underlying object (otherwise we'll get
+ // double-destruction), so these equality operators should never be needed.
+ template<typename U> bool operator==(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator==(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+
+ PtrType m_ptr;
+ };
+
+ 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;
+ }
+
+ template<typename T> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o)
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ deleteOwnedPtr(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<U>& o)
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ deleteOwnedPtr(ptr);
+ return *this;
+ }
+
+ 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)
+ {
+ return a.get() == 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)
+ {
+ return a.get() != 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)
+ {
+ return p.get();
+ }
+
+} // namespace WTF
+
+using WTF::OwnPtr;
+
+#endif // WTF_OwnPtr_h
diff --git a/Source/JavaScriptCore/wtf/OwnPtrCommon.h b/Source/JavaScriptCore/wtf/OwnPtrCommon.h
new file mode 100644
index 000000000..16283aed2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/OwnPtrCommon.h
@@ -0,0 +1,74 @@
+/*
+ * 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
+ * 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_OwnPtrCommon_h
+#define WTF_OwnPtrCommon_h
+
+#if PLATFORM(WIN)
+typedef struct HBITMAP__* HBITMAP;
+typedef struct HBRUSH__* HBRUSH;
+typedef struct HDC__* HDC;
+typedef struct HFONT__* HFONT;
+typedef struct HPALETTE__* HPALETTE;
+typedef struct HPEN__* HPEN;
+typedef struct HRGN__* HRGN;
+#endif
+
+#if PLATFORM(EFL)
+typedef struct _Ecore_Evas Ecore_Evas;
+typedef struct _Ecore_Pipe Ecore_Pipe;
+typedef struct _Evas_Object Evas_Object;
+#endif
+
+namespace WTF {
+
+ template <typename T> inline void deleteOwnedPtr(T* ptr)
+ {
+ typedef char known[sizeof(T) ? 1 : -1];
+ if (sizeof(known))
+ delete ptr;
+ }
+
+#if PLATFORM(WIN)
+ void deleteOwnedPtr(HBITMAP);
+ void deleteOwnedPtr(HBRUSH);
+ void deleteOwnedPtr(HDC);
+ void deleteOwnedPtr(HFONT);
+ void deleteOwnedPtr(HPALETTE);
+ void deleteOwnedPtr(HPEN);
+ void deleteOwnedPtr(HRGN);
+#endif
+
+#if PLATFORM(EFL)
+ void deleteOwnedPtr(Ecore_Evas*);
+ void deleteOwnedPtr(Ecore_Pipe*);
+ void deleteOwnedPtr(Evas_Object*);
+#endif
+
+} // namespace WTF
+
+#endif // WTF_OwnPtrCommon_h
diff --git a/Source/JavaScriptCore/wtf/PackedIntVector.h b/Source/JavaScriptCore/wtf/PackedIntVector.h
new file mode 100644
index 000000000..76fa48a1d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PackedIntVector.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 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 PackedIntVector_h
+#define PackedIntVector_h
+
+#include "BitVector.h"
+
+namespace WTF {
+
+// This class allows you to create an array of integers, where those
+// integers have only a handful of bits each. It is not meant to be
+// efficient in time, but only in space. (Though making it efficient
+// in time for power-of-2 values of bitCount would not be difficult.)
+// Note that this does not work as expected for signed types, if you
+// are relying on the sign being preserved.
+
+template<typename T, unsigned bitCount>
+class PackedIntVector {
+public:
+ PackedIntVector()
+ {
+ ASSERT(bitCount);
+ ASSERT(bitCount < sizeof(void*) * 8);
+ }
+
+ PackedIntVector(const PackedIntVector& other)
+ : m_bits(other.m_bits)
+ {
+ }
+
+ PackedIntVector& operator=(const PackedIntVector& other)
+ {
+ m_bits = other.m_bits;
+ return *this;
+ }
+
+ size_t size() const
+ {
+ return m_bits.size() / bitCount;
+ }
+
+ void ensureSize(size_t numInts)
+ {
+ m_bits.ensureSize(numInts * bitCount);
+ }
+
+ void resize(size_t numInts)
+ {
+ m_bits.resize(numInts * bitCount);
+ }
+
+ void clearAll()
+ {
+ m_bits.clearAll();
+ }
+
+ T get(size_t index) const
+ {
+ uintptr_t result = 0;
+ for (unsigned subIndex = 0; subIndex < bitCount; ++subIndex) {
+ result <<= 1;
+ result |= (m_bits.quickGet(index * bitCount + subIndex) ? 1 : 0);
+ }
+ return static_cast<T>(result);
+ }
+
+ void set(size_t index, T value)
+ {
+ // Do arithmetic using uintptr_t, because (1) we know what it is
+ // (T might be an enum) and (2) it's the largest integer type that
+ // is likely to perform decently well.
+ uintptr_t myValue = static_cast<uintptr_t>(value);
+
+ // Preliminary sanity check that the value is not out of range.
+ ASSERT((myValue & mask()) == myValue);
+
+ for (unsigned subIndex = bitCount; subIndex-- > 0;) {
+ m_bits.quickSet(index * bitCount + subIndex, !!(myValue & 1));
+ myValue >>= 1;
+ }
+
+ // Final sanity check that we stored what the user thought we
+ // stored.
+ ASSERT(get(index) == value);
+ }
+private:
+ // This returns the mask, and is careful to not step on the wrap-around
+ // semantics of the shift amount (1 << 32 is 1 since 32 wraps to 0). There
+ // is the separate question of why you would ever use this to store 32-bit
+ // or 64-bit values, but it's probably better to have this work as expected
+ // in such situations regardless.
+ static uintptr_t mask() { return (static_cast<uintptr_t>(2) << (bitCount - 1)) - 1; }
+
+ // Stores integers bit by bit in big endian.
+ BitVector m_bits;
+};
+
+} // namespace WTF
+
+using WTF::PackedIntVector;
+
+#endif // PackedIntVector_h
+
diff --git a/Source/JavaScriptCore/wtf/PageAllocation.h b/Source/JavaScriptCore/wtf/PageAllocation.h
new file mode 100644
index 000000000..18d31880c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageAllocation.h
@@ -0,0 +1,120 @@
+/*
+ * 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/OSAllocator.h>
+#include <wtf/PageBlock.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/VMTags.h>
+#include <algorithm>
+
+#if OS(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+#endif
+
+#if OS(WINDOWS)
+#include <malloc.h>
+#include <windows.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).
+*/
+
+class PageAllocation : private PageBlock {
+public:
+ PageAllocation()
+ {
+ }
+
+ using PageBlock::size;
+ using PageBlock::base;
+
+#ifndef __clang__
+ using PageBlock::operator bool;
+#else
+ // FIXME: This is a workaround for <rdar://problem/8876150>, wherein Clang incorrectly emits an access
+ // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+ operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+ static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
+ }
+
+ void deallocate()
+ {
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageAllocation tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+ OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
+ }
+
+private:
+ PageAllocation(void* base, size_t size)
+ : PageBlock(base, size, false)
+ {
+ }
+};
+
+} // namespace WTF
+
+using WTF::PageAllocation;
+
+#endif // PageAllocation_h
diff --git a/Source/JavaScriptCore/wtf/PageAllocationAligned.cpp b/Source/JavaScriptCore/wtf/PageAllocationAligned.cpp
new file mode 100644
index 000000000..6f54710d0
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageAllocationAligned.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "config.h"
+#include "PageAllocationAligned.h"
+
+namespace WTF {
+
+PageAllocationAligned PageAllocationAligned::allocate(size_t size, size_t alignment, OSAllocator::Usage usage, bool writable, bool executable)
+{
+ ASSERT(isPageAligned(size));
+ ASSERT(isPageAligned(alignment));
+ ASSERT(isPowerOfTwo(alignment));
+ ASSERT(size >= alignment);
+ size_t alignmentMask = alignment - 1;
+
+#if OS(DARWIN)
+ int flags = VM_FLAGS_ANYWHERE;
+ if (usage != OSAllocator::UnknownUsage)
+ flags |= usage;
+ int protection = PROT_READ;
+ if (writable)
+ protection |= PROT_WRITE;
+ if (executable)
+ protection |= PROT_EXEC;
+
+ vm_address_t address = 0;
+ vm_map(current_task(), &address, size, alignmentMask, flags, MEMORY_OBJECT_NULL, 0, FALSE, protection, PROT_READ | PROT_WRITE | PROT_EXEC, VM_INHERIT_DEFAULT);
+ return PageAllocationAligned(reinterpret_cast<void*>(address), size);
+#else
+ size_t alignmentDelta = alignment - pageSize();
+
+ // Resererve with suffcient additional VM to correctly align.
+ size_t reservationSize = size + alignmentDelta;
+ void* reservationBase = OSAllocator::reserveUncommitted(reservationSize, usage, writable, executable);
+
+ // Select an aligned region within the reservation and commit.
+ void* alignedBase = reinterpret_cast<uintptr_t>(reservationBase) & alignmentMask
+ ? reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(reservationBase) & ~alignmentMask) + alignment)
+ : reservationBase;
+ OSAllocator::commit(alignedBase, size, writable, executable);
+
+ return PageAllocationAligned(alignedBase, size, reservationBase, reservationSize);
+#endif
+}
+
+void PageAllocationAligned::deallocate()
+{
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageAllocationAligned tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+#if OS(DARWIN)
+ vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(tmp.base()), tmp.size());
+#else
+ ASSERT(tmp.m_reservation.contains(tmp.base(), tmp.size()));
+ OSAllocator::decommitAndRelease(tmp.m_reservation.base(), tmp.m_reservation.size(), tmp.base(), tmp.size());
+#endif
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/PageAllocationAligned.h b/Source/JavaScriptCore/wtf/PageAllocationAligned.h
new file mode 100644
index 000000000..c018dabd8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageAllocationAligned.h
@@ -0,0 +1,70 @@
+/*
+ * 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 PageAllocationAligned_h
+#define PageAllocationAligned_h
+
+#include <wtf/OSAllocator.h>
+#include <wtf/PageReservation.h>
+
+namespace WTF {
+
+class PageAllocationAligned : private PageBlock {
+public:
+ PageAllocationAligned()
+ {
+ }
+
+ using PageBlock::operator bool;
+ using PageBlock::size;
+ using PageBlock::base;
+
+ static PageAllocationAligned allocate(size_t size, size_t alignment, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false);
+
+ void deallocate();
+
+private:
+#if OS(DARWIN)
+ PageAllocationAligned(void* base, size_t size)
+ : PageBlock(base, size, false)
+ {
+ }
+#else
+ PageAllocationAligned(void* base, size_t size, void* reservationBase, size_t reservationSize)
+ : PageBlock(base, size, false)
+ , m_reservation(reservationBase, reservationSize, false)
+ {
+ }
+
+ PageBlock m_reservation;
+#endif
+};
+
+
+} // namespace WTF
+
+using WTF::PageAllocationAligned;
+
+#endif // PageAllocationAligned_h
diff --git a/Source/JavaScriptCore/wtf/PageBlock.cpp b/Source/JavaScriptCore/wtf/PageBlock.cpp
new file mode 100644
index 000000000..f7c546356
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageBlock.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "config.h"
+#include "PageBlock.h"
+
+#if OS(UNIX)
+#include <unistd.h>
+#endif
+
+#if OS(WINDOWS)
+#include <malloc.h>
+#include <windows.h>
+#endif
+
+namespace WTF {
+
+static size_t s_pageSize;
+
+#if OS(UNIX)
+
+inline size_t systemPageSize()
+{
+ return getpagesize();
+}
+
+#elif OS(WINDOWS)
+
+inline size_t systemPageSize()
+{
+ static size_t size = 0;
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ size = system_info.dwPageSize;
+ return size;
+}
+
+#endif
+
+size_t pageSize()
+{
+ if (!s_pageSize)
+ s_pageSize = systemPageSize();
+ ASSERT(isPowerOfTwo(s_pageSize));
+ return s_pageSize;
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/PageBlock.h b/Source/JavaScriptCore/wtf/PageBlock.h
new file mode 100644
index 000000000..e17c5460a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageBlock.h
@@ -0,0 +1,87 @@
+/*
+ * 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 PageBlock_h
+#define PageBlock_h
+
+namespace WTF {
+
+size_t pageSize();
+inline bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); }
+inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
+inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
+
+class PageBlock {
+public:
+ PageBlock();
+ PageBlock(const PageBlock&);
+ PageBlock(void*, size_t, bool hasGuardPages);
+
+ void* base() const { return m_base; }
+ size_t size() const { return m_size; }
+
+ operator bool() const { return !!m_realBase; }
+
+ bool contains(void* containedBase, size_t containedSize)
+ {
+ return containedBase >= m_base
+ && (static_cast<char*>(containedBase) + containedSize) <= (static_cast<char*>(m_base) + m_size);
+ }
+
+private:
+ void* m_realBase;
+ void* m_base;
+ size_t m_size;
+};
+
+inline PageBlock::PageBlock()
+ : m_realBase(0)
+ , m_base(0)
+ , m_size(0)
+{
+}
+
+inline PageBlock::PageBlock(const PageBlock& other)
+ : m_realBase(other.m_realBase)
+ , m_base(other.m_base)
+ , m_size(other.m_size)
+{
+}
+
+inline PageBlock::PageBlock(void* base, size_t size, bool hasGuardPages)
+ : m_realBase(base)
+ , m_base(static_cast<char*>(base) + ((base && hasGuardPages) ? pageSize() : 0))
+ , m_size(size)
+{
+}
+
+} // namespace WTF
+
+using WTF::pageSize;
+using WTF::isPageAligned;
+using WTF::isPageAligned;
+using WTF::isPowerOfTwo;
+
+#endif // PageBlock_h
diff --git a/Source/JavaScriptCore/wtf/PageReservation.h b/Source/JavaScriptCore/wtf/PageReservation.h
new file mode 100644
index 000000000..77783ebcc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PageReservation.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+
+ 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.
+*/
+
+class PageReservation : private PageBlock {
+public:
+ PageReservation()
+ : m_committed(0)
+ , m_writable(false)
+ , m_executable(false)
+ {
+ }
+
+ using PageBlock::base;
+ using PageBlock::size;
+
+#ifndef __clang__
+ using PageBlock::operator bool;
+#else
+ // FIXME: This is a workaround for <rdar://problem/8876150>, wherein Clang incorrectly emits an access
+ // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+ operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+ void commit(void* start, size_t size)
+ {
+ ASSERT(*this);
+ ASSERT(isPageAligned(start));
+ ASSERT(isPageAligned(size));
+ ASSERT(contains(start, size));
+
+ m_committed += size;
+ OSAllocator::commit(start, size, m_writable, m_executable);
+ }
+
+ void decommit(void* start, size_t size)
+ {
+ ASSERT(*this);
+ ASSERT(isPageAligned(start));
+ ASSERT(isPageAligned(size));
+ ASSERT(contains(start, size));
+
+ m_committed -= size;
+ OSAllocator::decommit(start, size);
+ }
+
+ size_t committed()
+ {
+ return m_committed;
+ }
+
+ static PageReservation reserve(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageReservation(OSAllocator::reserveUncommitted(size, usage, writable, executable), size, writable, executable, false);
+ }
+
+ static PageReservation reserveWithGuardPages(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageReservation(OSAllocator::reserveUncommitted(size + pageSize() * 2, usage, writable, executable, true), size, writable, executable, true);
+ }
+
+ void deallocate()
+ {
+ ASSERT(!m_committed);
+
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageReservation tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+ OSAllocator::releaseDecommitted(tmp.base(), tmp.size());
+ }
+
+private:
+ PageReservation(void* base, size_t size, bool writable, bool executable, bool hasGuardPages)
+ : PageBlock(base, size, hasGuardPages)
+ , m_committed(0)
+ , m_writable(writable)
+ , m_executable(executable)
+ {
+ }
+
+ size_t m_committed;
+ bool m_writable;
+ bool m_executable;
+};
+
+}
+
+using WTF::PageReservation;
+
+#endif // PageReservation_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobs.h b/Source/JavaScriptCore/wtf/ParallelJobs.h
new file mode 100644
index 000000000..92b9c5b5b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ParallelJobs.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 ParallelJobs_h
+#define ParallelJobs_h
+
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "RefPtr.h"
+#include <wtf/Vector.h>
+
+// Usage:
+//
+// // Initialize parallel jobs
+// ParallelJobs<TypeOfParameter> parallelJobs(&worker [, requestedNumberOfJobs]);
+//
+// // Fill the parameter array
+// for(i = 0; i < parallelJobs.numberOfJobs(); ++i) {
+// TypeOfParameter& params = parallelJobs.parameter(i);
+// params.attr1 = localVars ...
+// ...
+// }
+//
+// // Execute parallel jobs
+// parallelJobs.execute();
+//
+
+#if ENABLE(THREADING_GENERIC)
+#include "ParallelJobsGeneric.h"
+
+#elif ENABLE(THREADING_OPENMP)
+#include "ParallelJobsOpenMP.h"
+
+#elif ENABLE(THREADING_LIBDISPATCH)
+#include "ParallelJobsLibdispatch.h"
+
+#else
+#error "No parallel processing API for ParallelJobs"
+
+#endif
+
+namespace WTF {
+
+template<typename Type>
+class ParallelJobs {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*WorkerFunction)(Type*);
+
+ ParallelJobs(WorkerFunction func, int requestedJobNumber) :
+ m_parallelEnvironment(reinterpret_cast<ParallelEnvironment::ThreadFunction>(func), sizeof(Type), requestedJobNumber)
+ {
+ m_parameters.grow(m_parallelEnvironment.numberOfJobs());
+ ASSERT(numberOfJobs() == m_parameters.size());
+ }
+
+ size_t numberOfJobs()
+ {
+ return m_parameters.size();
+ }
+
+ Type& parameter(size_t i)
+ {
+ return m_parameters[i];
+ }
+
+ void execute()
+ {
+ m_parallelEnvironment.execute(reinterpret_cast<unsigned char*>(m_parameters.data()));
+ }
+
+private:
+ ParallelEnvironment m_parallelEnvironment;
+ Vector<Type> m_parameters;
+};
+
+} // namespace WTF
+
+using WTF::ParallelJobs;
+
+#endif // ParallelJobs_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp
new file mode 100644
index 000000000..b6207dc88
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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"
+
+#if ENABLE(THREADING_GENERIC)
+
+#include "ParallelJobs.h"
+#include "UnusedParam.h"
+
+#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD)
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#elif OS(LINUX) || OS(AIX) || OS(SOLARIS)
+#include <unistd.h>
+#elif OS(WINDOWS)
+#include <windows.h>
+#endif
+
+namespace WTF {
+
+Vector< RefPtr<ParallelEnvironment::ThreadPrivate> >* ParallelEnvironment::s_threadPool = 0;
+
+int ParallelEnvironment::s_maxNumberOfParallelThreads = -1;
+
+ParallelEnvironment::ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+{
+ ASSERT_ARG(requestedJobNumber, requestedJobNumber >= 1);
+
+ if (s_maxNumberOfParallelThreads == -1)
+ determineMaxNumberOfParallelThreads();
+
+ if (!requestedJobNumber || requestedJobNumber > s_maxNumberOfParallelThreads)
+ requestedJobNumber = static_cast<unsigned>(s_maxNumberOfParallelThreads);
+
+ if (!s_threadPool)
+ s_threadPool = new Vector< RefPtr<ThreadPrivate> >();
+
+ // The main thread should be also a worker.
+ int maxNumberOfNewThreads = requestedJobNumber - 1;
+
+ for (int i = 0; i < s_maxNumberOfParallelThreads && m_threads.size() < static_cast<unsigned>(maxNumberOfNewThreads); ++i) {
+ if (s_threadPool->size() < static_cast<unsigned>(i) + 1U)
+ s_threadPool->append(ThreadPrivate::create());
+
+ if ((*s_threadPool)[i]->tryLockFor(this))
+ m_threads.append((*s_threadPool)[i]);
+ }
+
+ m_numberOfJobs = m_threads.size() + 1;
+}
+
+void ParallelEnvironment::execute(void* parameters)
+{
+ unsigned char* currentParameter = static_cast<unsigned char*>(parameters);
+ size_t i;
+ for (i = 0; i < m_threads.size(); ++i) {
+ m_threads[i]->execute(m_threadFunction, currentParameter);
+ currentParameter += m_sizeOfParameter;
+ }
+
+ // The work for the main thread.
+ (*m_threadFunction)(currentParameter);
+
+ // Wait until all jobs are done.
+ for (i = 0; i < m_threads.size(); ++i)
+ m_threads[i]->waitForFinish();
+}
+
+void ParallelEnvironment::determineMaxNumberOfParallelThreads()
+{
+ const int defaultIfUnavailable = 2;
+#if OS(DARWIN) || OS(OPENBSD) || OS(NETBSD)
+ unsigned result;
+ size_t length = sizeof(result);
+ int name[] = {
+ CTL_HW,
+ HW_NCPU
+ };
+ int sysctlResult = sysctl(name, sizeof(name) / sizeof(int), &result, &length, 0, 0);
+ s_maxNumberOfParallelThreads = sysctlResult < 0 ? defaultIfUnavailable : result;
+#elif OS(LINUX) || OS(AIX) || OS(SOLARIS)
+ long sysconfResult = sysconf(_SC_NPROCESSORS_ONLN);
+ s_maxNumberOfParallelThreads = sysconfResult < 0 ? defaultIfUnavailable : static_cast<int>(sysconfResult);
+#elif OS(WINDOWS)
+ UNUSED_PARAM(defaultIfUnavailable);
+
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo(&sysInfo);
+ s_maxNumberOfParallelThreads = sysInfo.dwNumberOfProcessors;
+#else
+ s_maxNumberOfParallelThreads = defaultIfUnavailable;
+#endif
+}
+
+bool ParallelEnvironment::ThreadPrivate::tryLockFor(ParallelEnvironment* parent)
+{
+ bool locked = m_mutex.tryLock();
+
+ if (!locked)
+ return false;
+
+ if (m_parent) {
+ m_mutex.unlock();
+ return false;
+ }
+
+ if (!m_threadID)
+ m_threadID = createThread(&ParallelEnvironment::ThreadPrivate::workerThread, this, "Parallel worker");
+
+ if (m_threadID)
+ m_parent = parent;
+
+ m_mutex.unlock();
+ return m_threadID;
+}
+
+void ParallelEnvironment::ThreadPrivate::execute(ThreadFunction threadFunction, void* parameters)
+{
+ MutexLocker lock(m_mutex);
+
+ m_threadFunction = threadFunction;
+ m_parameters = parameters;
+ m_running = true;
+ m_threadCondition.signal();
+}
+
+void ParallelEnvironment::ThreadPrivate::waitForFinish()
+{
+ MutexLocker lock(m_mutex);
+
+ while (m_running)
+ m_threadCondition.wait(m_mutex);
+}
+
+void* ParallelEnvironment::ThreadPrivate::workerThread(void* threadData)
+{
+ ThreadPrivate* sharedThread = reinterpret_cast<ThreadPrivate*>(threadData);
+ MutexLocker lock(sharedThread->m_mutex);
+
+ while (sharedThread->m_threadID) {
+ if (sharedThread->m_running) {
+ (*sharedThread->m_threadFunction)(sharedThread->m_parameters);
+ sharedThread->m_running = false;
+ sharedThread->m_parent = 0;
+ sharedThread->m_threadCondition.signal();
+ }
+
+ sharedThread->m_threadCondition.wait(sharedThread->m_mutex);
+ }
+ return 0;
+}
+
+} // namespace WTF
+#endif // ENABLE(THREADING_GENERIC)
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h
new file mode 100644
index 000000000..dab6dd9fb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 ParallelJobsGeneric_h
+#define ParallelJobsGeneric_h
+
+#if ENABLE(THREADING_GENERIC)
+
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction, size_t sizeOfParameter, int requestedJobNumber);
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(void* parameters);
+
+ class ThreadPrivate : public RefCounted<ThreadPrivate> {
+ public:
+ ThreadPrivate()
+ : m_threadID(0)
+ , m_running(false)
+ , m_parent(0)
+ {
+ }
+
+ bool tryLockFor(ParallelEnvironment*);
+
+ void execute(ThreadFunction, void*);
+
+ void waitForFinish();
+
+ static PassRefPtr<ThreadPrivate> create()
+ {
+ return adoptRef(new ThreadPrivate());
+ }
+
+ static void* workerThread(void*);
+
+ private:
+ ThreadIdentifier m_threadID;
+ bool m_running;
+ ParallelEnvironment* m_parent;
+
+ mutable Mutex m_mutex;
+ ThreadCondition m_threadCondition;
+
+ ThreadFunction m_threadFunction;
+ void* m_parameters;
+ };
+
+private:
+ static void determineMaxNumberOfParallelThreads();
+
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+
+ Vector< RefPtr<ThreadPrivate> > m_threads;
+ static Vector< RefPtr<ThreadPrivate> >* s_threadPool;
+ static int s_maxNumberOfParallelThreads;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_GENERIC)
+
+
+#endif // ParallelJobsGeneric_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h b/Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h
new file mode 100644
index 000000000..ca7d9a4e8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 ParallelJobsLibdispatch_h
+#define ParallelJobsLibdispatch_h
+
+#if ENABLE(THREADING_LIBDISPATCH)
+
+#include <dispatch/dispatch.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber)
+ : m_threadFunction(threadFunction)
+ , m_sizeOfParameter(sizeOfParameter)
+ , m_numberOfJobs(requestedJobNumber)
+ {
+ // We go with the requested number of jobs. libdispatch will distribute the work optimally.
+ ASSERT_ARG(requestedJobNumber, requestedJobNumber > 0);
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ static dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_apply(m_numberOfJobs, globalQueue, ^(size_t i) { (*m_threadFunction)(parameters + (m_sizeOfParameter * i)); });
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_LIBDISPATCH)
+
+#endif // ParallelJobsLibdispatch_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h b/Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h
new file mode 100644
index 000000000..706bd8065
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 ParallelJobsOpenMP_h
+#define ParallelJobsOpenMP_h
+
+#if ENABLE(THREADING_OPENMP)
+
+#include <omp.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+ WTF_MAKE_NONCOPYABLE(ParallelEnvironment);
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ int maxNumberOfThreads = omp_get_max_threads();
+
+ if (!requestedJobNumber || requestedJobNumber > maxNumberOfThreads)
+ requestedJobNumber = maxNumberOfThreads;
+
+ ASSERT(requestedJobNumber > 0);
+
+ m_numberOfJobs = requestedJobNumber;
+
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ omp_set_num_threads(m_numberOfJobs);
+
+#pragma omp parallel for
+ for (int i = 0; i < m_numberOfJobs; ++i)
+ (*m_threadFunction)(parameters + i * m_sizeOfParameter);
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_OPENMP)
+
+#endif // ParallelJobsOpenMP_h
diff --git a/Source/JavaScriptCore/wtf/PassOwnArrayPtr.h b/Source/JavaScriptCore/wtf/PassOwnArrayPtr.h
new file mode 100644
index 000000000..3748f18c6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PassOwnArrayPtr.h
@@ -0,0 +1,169 @@
+/*
+ * 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 "TypeTraits.h"
+
+namespace WTF {
+
+template<typename T> class OwnArrayPtr;
+template<typename T> class PassOwnArrayPtr;
+template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*);
+template<typename T> void deleteOwnedArrayPtr(T* ptr);
+
+template<typename T> class PassOwnArrayPtr {
+public:
+ typedef T* PtrType;
+
+ PassOwnArrayPtr() : m_ptr(0) { }
+ PassOwnArrayPtr(std::nullptr_t) : 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; }
+
+ 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.
+ typedef PtrType PassOwnArrayPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnArrayPtr::m_ptr : 0; }
+
+ PassOwnArrayPtr& operator=(const PassOwnArrayPtr&) { COMPILE_ASSERT(!sizeof(T*), PassOwnArrayPtr_should_never_be_assigned_to); return *this; }
+
+ template<typename U> friend PassOwnArrayPtr<U> adoptArrayPtr(U*);
+
+private:
+ explicit PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { }
+
+ mutable PtrType m_ptr;
+};
+
+template<typename T> inline typename PassOwnArrayPtr<T>::PtrType PassOwnArrayPtr<T>::leakPtr() const
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+}
+
+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> inline void deleteOwnedArrayPtr(T* ptr)
+{
+ typedef char known[sizeof(T) ? 1 : -1];
+ if (sizeof(known))
+ delete [] 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/Source/JavaScriptCore/wtf/PassOwnPtr.h b/Source/JavaScriptCore/wtf/PassOwnPtr.h
new file mode 100644
index 000000000..262ac3bfe
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PassOwnPtr.h
@@ -0,0 +1,172 @@
+/*
+ * 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 WTF_PassOwnPtr_h
+#define WTF_PassOwnPtr_h
+
+#include "Assertions.h"
+#include "NullPtr.h"
+#include "OwnPtrCommon.h"
+#include "TypeTraits.h"
+
+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 PassOwnPtr;
+ template<typename T> PassOwnPtr<T> adoptPtr(T*);
+
+ template<typename T> class PassOwnPtr {
+ public:
+ typedef typename RemovePointer<T>::Type ValueType;
+ typedef ValueType* PtrType;
+
+ PassOwnPtr() : m_ptr(0) { }
+ PassOwnPtr(std::nullptr_t) : 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 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; }
+
+ PtrType leakPtr() const WARN_UNUSED_RETURN;
+
+ ValueType& 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.
+ typedef PtrType PassOwnPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnPtr::m_ptr : 0; }
+
+ PassOwnPtr& operator=(const PassOwnPtr&) { COMPILE_ASSERT(!sizeof(T*), PassOwnPtr_should_never_be_assigned_to); return *this; }
+
+ template<typename U> friend PassOwnPtr<U> adoptPtr(U*);
+
+ private:
+ explicit PassOwnPtr(PtrType ptr) : m_ptr(ptr) { }
+
+ // We should never have two OwnPtrs for the same underlying object (otherwise we'll get
+ // double-destruction), so these equality operators should never be needed.
+ template<typename U> bool operator==(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator==(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+
+ mutable PtrType m_ptr;
+ };
+
+ template<typename T> inline typename PassOwnPtr<T>::PtrType PassOwnPtr<T>::leakPtr() const
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+ 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)
+ {
+ return a.get() == b.get();
+ }
+
+ 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)
+ {
+ return a.get() == 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)
+ {
+ return a.get() != b.get();
+ }
+
+ 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)
+ {
+ return a.get() != b.get();
+ }
+
+ 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)
+ {
+ return a != b.get();
+ }
+
+ 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 adoptPtr(static_cast<T*>(p.leakPtr()));
+ }
+
+ template<typename T, typename U> inline PassOwnPtr<T> const_pointer_cast(const PassOwnPtr<U>& p)
+ {
+ return adoptPtr(const_cast<T*>(p.leakPtr()));
+ }
+
+ template<typename T> inline T* getPtr(const PassOwnPtr<T>& p)
+ {
+ return p.get();
+ }
+
+} // namespace WTF
+
+using WTF::PassOwnPtr;
+using WTF::adoptPtr;
+using WTF::const_pointer_cast;
+using WTF::static_pointer_cast;
+
+#endif // WTF_PassOwnPtr_h
diff --git a/Source/JavaScriptCore/wtf/PassRefPtr.h b/Source/JavaScriptCore/wtf/PassRefPtr.h
new file mode 100644
index 000000000..a13dee794
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PassRefPtr.h
@@ -0,0 +1,245 @@
+/*
+ * 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
+ * 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_PassRefPtr_h
+#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*);
+
+ inline void adopted(const void*) { }
+
+#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
+
+ template<typename T> REF_DEREF_INLINE void refIfNotNull(T* ptr)
+ {
+ if (LIKELY(ptr != 0))
+ ptr->ref();
+ }
+
+ template<typename T> REF_DEREF_INLINE void derefIfNotNull(T* ptr)
+ {
+ if (LIKELY(ptr != 0))
+ ptr->deref();
+ }
+
+ #undef REF_DEREF_INLINE
+
+ template<typename T> class PassRefPtr {
+ public:
+ 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 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<typename U> PassRefPtr(const RefPtr<U>&);
+
+ T* get() const { return m_ptr; }
+
+ 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.
+ typedef T* (PassRefPtr::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType() const { return m_ptr ? &PassRefPtr::m_ptr : 0; }
+
+ PassRefPtr& operator=(const PassRefPtr&) { COMPILE_ASSERT(!sizeof(T*), PassRefPtr_should_never_be_assigned_to); return *this; }
+
+ friend PassRefPtr adoptRef<T>(T*);
+
+ private:
+ // adopting constructor
+ 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 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 {
+ public:
+ NonNullPassRefPtr(T* ptr)
+ : m_ptr(ptr)
+ {
+ ASSERT(m_ptr);
+ m_ptr->ref();
+ }
+
+ template<typename U> NonNullPassRefPtr(const RefPtr<U>& o)
+ : m_ptr(o.get())
+ {
+ ASSERT(m_ptr);
+ m_ptr->ref();
+ }
+
+ NonNullPassRefPtr(const NonNullPassRefPtr& o)
+ : m_ptr(o.leakRef())
+ {
+ ASSERT(m_ptr);
+ }
+
+ template<typename U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
+ {
+ ASSERT(m_ptr);
+ }
+
+ template<typename U> NonNullPassRefPtr(const PassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
+ {
+ ASSERT(m_ptr);
+ }
+
+ ALWAYS_INLINE ~NonNullPassRefPtr() { derefIfNotNull(m_ptr); }
+
+ T* get() const { return m_ptr; }
+
+ 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; }
+
+ NonNullPassRefPtr& operator=(const NonNullPassRefPtr&) { COMPILE_ASSERT(!sizeof(T*), NonNullPassRefPtr_should_never_be_assigned_to); return *this; }
+
+ private:
+ mutable T* m_ptr;
+ };
+
+ 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 T* PassRefPtr<T>::leakRef() const
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+ 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)
+ {
+ return a.get() == b.get();
+ }
+
+ 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)
+ {
+ return a.get() == 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)
+ {
+ return a.get() != b.get();
+ }
+
+ 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)
+ {
+ return a.get() != b.get();
+ }
+
+ 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)
+ {
+ return a != b.get();
+ }
+
+ 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)
+ {
+ return adoptRef(static_cast<T*>(p.leakRef()));
+ }
+
+ template<typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p)
+ {
+ return adoptRef(const_cast<T*>(p.leakRef()));
+ }
+
+ template<typename T> inline T* getPtr(const PassRefPtr<T>& p)
+ {
+ return p.get();
+ }
+
+} // namespace WTF
+
+using WTF::PassRefPtr;
+using WTF::NonNullPassRefPtr;
+using WTF::adoptRef;
+using WTF::static_pointer_cast;
+using WTF::const_pointer_cast;
+
+#endif // WTF_PassRefPtr_h
diff --git a/Source/JavaScriptCore/wtf/PassTraits.h b/Source/JavaScriptCore/wtf/PassTraits.h
new file mode 100644
index 000000000..346273486
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PassTraits.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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 WTF_PassTraits_h
+#define WTF_PassTraits_h
+
+#include "OwnPtr.h"
+#include "RefPtr.h"
+
+// The PassTraits template exists to help optimize (or make possible) use
+// of WTF data structures with WTF smart pointers that have a Pass
+// variant for transfer of ownership
+
+namespace WTF {
+
+template<typename T> struct PassTraits {
+ typedef T Type;
+ typedef T PassType;
+ static PassType transfer(Type& value) { return value; }
+};
+
+template<typename T> struct PassTraits<OwnPtr<T> > {
+ typedef OwnPtr<T> Type;
+ typedef PassOwnPtr<T> PassType;
+ static PassType transfer(Type& value) { return value.release(); }
+};
+
+template<typename T> struct PassTraits<RefPtr<T> > {
+ typedef RefPtr<T> Type;
+ typedef PassRefPtr<T> PassType;
+ static PassType transfer(Type& value) { return value.release(); }
+};
+
+} // namespace WTF
+
+using WTF::PassTraits;
+
+#endif // WTF_PassTraits_h
diff --git a/Source/JavaScriptCore/wtf/Platform.h b/Source/JavaScriptCore/wtf/Platform.h
new file mode 100644
index 000000000..bb1462e1e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Platform.h
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010, 2011 Research In Motion Limited. 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_Platform_h
+#define WTF_Platform_h
+
+/* Include compiler specific macros */
+#include "Compiler.h"
+
+/* ==== PLATFORM handles OS, operating environment, graphics API, and
+ CPU. This macro will be phased out in favor of platform adaptation
+ macros, policy decision macros, and top-level port definitions. ==== */
+#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE && WTF_PLATFORM_##WTF_FEATURE)
+
+
+/* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
+
+/* CPU() - the target CPU architecture */
+#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE && WTF_CPU_##WTF_FEATURE)
+/* HAVE() - specific system features (headers, functions or similar) that are present or not */
+#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE)
+/* OS() - underlying operating system; only to be used for mandated low-level services like
+ virtual memory, not to choose a GUI toolkit */
+#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE && WTF_OS_##WTF_FEATURE)
+
+
+/* ==== Policy decision macros: these define policy choices for a particular port. ==== */
+
+/* USE() - use a particular third-party library or optional OS service */
+#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE)
+/* ENABLE() - turn on a specific feature of WebKit */
+#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE)
+
+
+/* ==== CPU() - the target CPU architecture ==== */
+
+/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
+
+/* CPU(ALPHA) - DEC Alpha */
+#if defined(__alpha__)
+#define WTF_CPU_ALPHA 1
+#endif
+
+/* 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(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__) \
+ || defined(__PPC__) \
+ || defined(__powerpc__) \
+ || defined(__powerpc) \
+ || defined(__POWERPC__) \
+ || defined(_M_PPC) \
+ || defined(__PPC)
+#define WTF_CPU_PPC 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* CPU(PPC64) - PowerPC 64-bit */
+#if defined(__ppc64__) \
+ || defined(__PPC64__)
+#define WTF_CPU_PPC64 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* CPU(SH4) - SuperH SH-4 */
+#if defined(__SH4__)
+#define WTF_CPU_SH4 1
+#endif
+
+/* CPU(SPARC32) - SPARC 32-bit */
+#if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
+#define WTF_CPU_SPARC32 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* CPU(SPARC64) - SPARC 64-bit */
+#if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
+#define WTF_CPU_SPARC64 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
+#if CPU(SPARC32) || CPU(SPARC64)
+#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 */
+#if defined(__i386__) \
+ || defined(i386) \
+ || defined(_M_IX86) \
+ || defined(_X86_) \
+ || defined(__THW_INTEL)
+#define WTF_CPU_X86 1
+#endif
+
+/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
+#if defined(__x86_64__) \
+ || defined(_M_X64)
+#define WTF_CPU_X86_64 1
+#endif
+
+/* CPU(ARM) - ARM, any version*/
+#if defined(arm) \
+ || defined(__arm__) \
+ || defined(ARM) \
+ || defined(_ARM_)
+#define WTF_CPU_ARM 1
+
+#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
+
+#endif
+
+#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
+
+/* Set WTF_ARM_ARCH_VERSION */
+#if defined(__ARM_ARCH_4__) \
+ || defined(__ARM_ARCH_4T__) \
+ || defined(__MARM_ARMV4__) \
+ || defined(_ARMV4I_)
+#define WTF_ARM_ARCH_VERSION 4
+
+#elif defined(__ARM_ARCH_5__) \
+ || defined(__ARM_ARCH_5T__) \
+ || 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__) \
+ || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__) \
+ || defined(__ARM_ARCH_6T2__) \
+ || defined(__ARMV6__)
+#define WTF_ARM_ARCH_VERSION 6
+
+#elif defined(__ARM_ARCH_7A__) \
+ || defined(__ARM_ARCH_7R__)
+#define WTF_ARM_ARCH_VERSION 7
+
+/* RVCT sets _TARGET_ARCH_ARM */
+#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
+
+#endif
+
+/* Set WTF_THUMB_ARCH_VERSION */
+#if defined(__ARM_ARCH_4T__)
+#define WTF_THUMB_ARCH_VERSION 1
+
+#elif defined(__ARM_ARCH_5T__) \
+ || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__)
+#define WTF_THUMB_ARCH_VERSION 2
+
+#elif defined(__ARM_ARCH_6J__) \
+ || defined(__ARM_ARCH_6K__) \
+ || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__) \
+ || defined(__ARM_ARCH_6M__)
+#define WTF_THUMB_ARCH_VERSION 3
+
+#elif defined(__ARM_ARCH_6T2__) \
+ || defined(__ARM_ARCH_7__) \
+ || defined(__ARM_ARCH_7A__) \
+ || defined(__ARM_ARCH_7R__) \
+ || defined(__ARM_ARCH_7M__)
+#define WTF_THUMB_ARCH_VERSION 4
+
+/* RVCT sets __TARGET_ARCH_THUMB */
+#elif defined(__TARGET_ARCH_THUMB)
+#define WTF_THUMB_ARCH_VERSION __TARGET_ARCH_THUMB
+
+#else
+#define WTF_THUMB_ARCH_VERSION 0
+#endif
+
+
+/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
+/* On ARMv5 and below the natural alignment is required.
+ And there are some other differences for v5 or earlier. */
+#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
+#define WTF_CPU_ARMV5_OR_LOWER 1
+#endif
+
+
+/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
+/* Only one of these will be defined. */
+#if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
+# if defined(thumb2) || defined(__thumb2__) \
+ || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+# define WTF_CPU_ARM_TRADITIONAL 0
+# define WTF_CPU_ARM_THUMB2 1
+# elif WTF_ARM_ARCH_AT_LEAST(4)
+# define WTF_CPU_ARM_TRADITIONAL 1
+# define WTF_CPU_ARM_THUMB2 0
+# else
+# error "Not supported ARM architecture"
+# endif
+#elif CPU(ARM_TRADITIONAL) && CPU(ARM_THUMB2) /* Sanity Check */
+# error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
+#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
+
+#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
+#define WTF_CPU_ARM_NEON 1
+#endif
+
+#endif /* ARM */
+
+#if CPU(ARM) || CPU(MIPS) || CPU(SH4)
+#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
+#endif
+
+/* ==== OS() - underlying operating system; only to be used for mandated low-level services like
+ virtual memory, not to choose a GUI toolkit ==== */
+
+/* OS(ANDROID) - Android */
+#ifdef ANDROID
+#define WTF_OS_ANDROID 1
+#endif
+
+/* OS(AIX) - AIX */
+#ifdef _AIX
+#define WTF_OS_AIX 1
+#endif
+
+/* OS(DARWIN) - Any Darwin-based OS, including Mac OS X and iPhone OS */
+#ifdef __APPLE__
+#define WTF_OS_DARWIN 1
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+#include <TargetConditionals.h>
+#endif
+
+/* 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_IOS 1
+#elif OS(DARWIN) && defined(TARGET_OS_MAC) && TARGET_OS_MAC
+#define WTF_OS_MAC_OS_X 1
+/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+#define BUILDING_ON_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define BUILDING_ON_SNOW_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+#define BUILDING_ON_LION 1
+#endif
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
+#define TARGETING_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+#define TARGETING_SNOW_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+#define TARGETING_LION 1
+#endif
+#endif
+
+/* OS(FREEBSD) - FreeBSD */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#define WTF_OS_FREEBSD 1
+#endif
+
+/* OS(LINUX) - Linux */
+#ifdef __linux__
+#define WTF_OS_LINUX 1
+#endif
+
+/* OS(NETBSD) - NetBSD */
+#if defined(__NetBSD__)
+#define WTF_OS_NETBSD 1
+#endif
+
+/* OS(OPENBSD) - OpenBSD */
+#ifdef __OpenBSD__
+#define WTF_OS_OPENBSD 1
+#endif
+
+/* OS(QNX) - QNX */
+#if defined(__QNXNTO__)
+#define WTF_OS_QNX 1
+#endif
+
+/* OS(SOLARIS) - Solaris */
+#if defined(sun) || defined(__sun)
+#define WTF_OS_SOLARIS 1
+#endif
+
+/* OS(WINCE) - Windows CE; note that for this platform OS(WINDOWS) is also defined */
+#if defined(_WIN32_WCE)
+#define WTF_OS_WINCE 1
+#endif
+
+/* OS(WINDOWS) - Any version of Windows */
+#if defined(WIN32) || defined(_WIN32)
+#define WTF_OS_WINDOWS 1
+#endif
+
+/* OS(UNIX) - Any Unix-like system */
+#if OS(AIX) \
+ || OS(ANDROID) \
+ || OS(DARWIN) \
+ || OS(FREEBSD) \
+ || OS(LINUX) \
+ || OS(NETBSD) \
+ || OS(OPENBSD) \
+ || OS(QNX) \
+ || OS(SOLARIS) \
+ || defined(unix) \
+ || defined(__unix) \
+ || defined(__unix__)
+#define WTF_OS_UNIX 1
+#endif
+
+/* Operating environments */
+
+/* FIXME: these are all mixes of OS, operating environment and policy choices. */
+/* PLATFORM(CHROMIUM) */
+/* PLATFORM(QT) */
+/* PLATFORM(WX) */
+/* PLATFORM(GTK) */
+/* PLATFORM(BLACKBERRY) */
+/* PLATFORM(MAC) */
+/* PLATFORM(WIN) */
+#if defined(BUILDING_CHROMIUM__)
+#define WTF_PLATFORM_CHROMIUM 1
+#elif defined(BUILDING_QT__)
+#define WTF_PLATFORM_QT 1
+#elif defined(BUILDING_WX__)
+#define WTF_PLATFORM_WX 1
+#elif defined(BUILDING_GTK__)
+#define WTF_PLATFORM_GTK 1
+#elif defined(BUILDING_BLACKBERRY__)
+#define WTF_PLATFORM_BLACKBERRY 1
+#elif OS(DARWIN)
+#define WTF_PLATFORM_MAC 1
+#elif OS(WINDOWS)
+#define WTF_PLATFORM_WIN 1
+#endif
+
+/* 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_IOS 1
+#endif
+
+/* PLATFORM(IOS_SIMULATOR) */
+#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
+#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IOS_SIMULATOR 1
+#else
+#define WTF_PLATFORM_IOS_SIMULATOR 0
+#endif
+
+#if !defined(WTF_PLATFORM_IOS)
+#define WTF_PLATFORM_IOS 0
+#endif
+
+/* Graphics engines */
+
+/* USE(CG) and PLATFORM(CI) */
+#if PLATFORM(MAC) || PLATFORM(IOS)
+#define WTF_USE_CG 1
+#endif
+#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WIN) && USE(CG))
+#define WTF_USE_CA 1
+#endif
+
+/* USE(SKIA) for Win/Linux, CG for Mac, unless enabled */
+#if PLATFORM(CHROMIUM)
+#if OS(DARWIN)
+#if USE(SKIA_ON_MAC_CHROMIUM)
+#define WTF_USE_SKIA 1
+#else
+#define WTF_USE_CG 1
+#endif
+#define WTF_USE_ATSUI 1
+#define WTF_USE_CORE_TEXT 1
+#define WTF_USE_ICCJPEG 1
+#else
+#define WTF_USE_SKIA 1
+#define WTF_USE_CHROMIUM_NET 1
+#endif
+#endif
+
+#if PLATFORM(BLACKBERRY)
+#define ENABLE_DRAG_SUPPORT 0
+#define USE_SYSTEM_MALLOC 1
+#define WTF_USE_MERSENNE_TWISTER_19937 1
+#define WTF_USE_SKIA 1
+#endif
+
+#if PLATFORM(GTK)
+#define WTF_USE_CAIRO 1
+#endif
+
+
+#if OS(WINCE)
+#include <ce_time.h>
+#define WTF_USE_MERSENNE_TWISTER_19937 1
+#endif
+
+/* On Windows, use QueryPerformanceCounter by default */
+#if OS(WINDOWS)
+#define WTF_USE_QUERY_PERFORMANCE_COUNTER 1
+#endif
+
+#if OS(WINCE) && !PLATFORM(QT)
+#define NOMINMAX /* Windows min and max conflict with standard macros */
+#define NOSHLWAPI /* shlwapi.h not available on WinCe */
+
+/* MSDN documentation says these functions are provided with uspce.lib. But we cannot find this file. */
+#define __usp10__ /* disable "usp10.h" */
+
+#define _INC_ASSERT /* disable "assert.h" */
+#define assert(x)
+
+#endif /* OS(WINCE) && !PLATFORM(QT) */
+
+#if PLATFORM(QT)
+#ifndef WTF_USE_ICU_UNICODE
+#define WTF_USE_QT4_UNICODE 1
+#endif
+#elif OS(WINCE)
+#define WTF_USE_WINCE_UNICODE 1
+#elif PLATFORM(GTK)
+/* The GTK+ Unicode backend is configurable */
+#else
+#define WTF_USE_ICU_UNICODE 1
+#endif
+
+#if PLATFORM(MAC) && !PLATFORM(IOS)
+#if !defined(BUILDING_ON_LEOPARD) && CPU(X86_64)
+#define WTF_USE_PLUGIN_HOST_PROCESS 1
+#endif
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define ENABLE_GESTURE_EVENTS 1
+#define ENABLE_RUBBER_BANDING 1
+#define WTF_USE_SCROLLBAR_PAINTER 1
+#endif
+#if !defined(ENABLE_JAVA_BRIDGE)
+#define ENABLE_JAVA_BRIDGE 1
+#endif
+#if !defined(ENABLE_DASHBOARD_SUPPORT)
+#define ENABLE_DASHBOARD_SUPPORT 1
+#endif
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
+#define HAVE_READLINE 1
+#define HAVE_RUNLOOP_TIMER 1
+#define ENABLE_FULLSCREEN_API 1
+#define ENABLE_SMOOTH_SCROLLING 1
+#define ENABLE_WEB_ARCHIVE 1
+#define ENABLE_WEB_AUDIO 1
+#define ENABLE_VIDEO_TRACK 1
+#endif /* PLATFORM(MAC) && !PLATFORM(IOS) */
+
+#if PLATFORM(CHROMIUM) && OS(DARWIN)
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
+
+#define WTF_USE_WK_SCROLLBAR_PAINTER 1
+#endif
+
+#if PLATFORM(IOS)
+#define DONT_FINALIZE_ON_MAIN_THREAD 1
+#endif
+
+#if PLATFORM(QT) && OS(DARWIN)
+#define WTF_USE_CF 1
+#define HAVE_DISPATCH_H 1
+#endif
+
+#if OS(DARWIN) && !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_DATA_TRANSFER_ITEMS 0
+#define ENABLE_FTPDIR 1
+#define ENABLE_GEOLOCATION 1
+#define ENABLE_ICONDATABASE 0
+#define ENABLE_INSPECTOR 1
+#define ENABLE_JAVA_BRIDGE 0
+#define ENABLE_NETSCAPE_PLUGIN_API 0
+#define ENABLE_ORIENTATION_EVENTS 1
+#define ENABLE_REPAINT_THROTTLING 1
+#define ENABLE_WEB_ARCHIVE 1
+#define HAVE_NETWORK_CFDATA_ARRAY_CALLBACK 1
+#define HAVE_PTHREAD_RWLOCK 1
+#define HAVE_READLINE 1
+#define HAVE_RUNLOOP_TIMER 0
+#define WTF_USE_CF 1
+#define WTF_USE_CFNETWORK 1
+#define WTF_USE_PTHREADS 1
+
+#if PLATFORM(IOS_SIMULATOR)
+ #define ENABLE_INTERPRETER 1
+ #define ENABLE_JIT 0
+ #define ENABLE_YARR_JIT 0
+#else
+ #define ENABLE_INTERPRETER 1
+ #define ENABLE_JIT 1
+ #define ENABLE_YARR_JIT 1
+#endif
+
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE)
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 0
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !PLATFORM(WIN_CAIRO)
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#if USE(CFNETWORK) || PLATFORM(MAC) || PLATFORM(IOS)
+#define WTF_USE_CFURLCACHE 1
+#define WTF_USE_CFURLSTORAGESESSIONS 1
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !PLATFORM(QT)
+#define ENABLE_WEB_ARCHIVE 1
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !PLATFORM(WIN_CAIRO) && !PLATFORM(QT)
+#define ENABLE_FULLSCREEN_API 1
+#endif
+
+#if PLATFORM(WX)
+#if !CPU(PPC)
+#define ENABLE_ASSEMBLER 1
+#define ENABLE_JIT 1
+#endif
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if OS(DARWIN)
+#define WTF_USE_CF 1
+#define WTF_USE_CORE_TEXT 1
+#define ENABLE_WEB_ARCHIVE 1
+#endif
+#endif
+
+#if PLATFORM(GTK)
+#if HAVE(PTHREAD_H)
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
+#endif
+#elif PLATFORM(QT) && OS(UNIX)
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
+#endif
+
+#if !defined(HAVE_ACCESSIBILITY)
+#if PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM)
+#define HAVE_ACCESSIBILITY 1
+#endif
+#endif /* !defined(HAVE_ACCESSIBILITY) */
+
+#if OS(UNIX)
+#define HAVE_SIGNAL_H 1
+#endif
+
+#if !defined(HAVE_VASPRINTF)
+#if !COMPILER(MSVC) && !COMPILER(RVCT) && !COMPILER(MINGW) && !(COMPILER(GCC) && OS(QNX))
+#define HAVE_VASPRINTF 1
+#endif
+#endif
+
+#if !defined(HAVE_STRNSTR)
+#if OS(DARWIN) || (OS(FREEBSD) && !defined(__GLIBC__))
+#define HAVE_STRNSTR 1
+#endif
+#endif
+
+#if !OS(WINDOWS) && !OS(SOLARIS) && !OS(QNX) \
+ && !OS(RVCT) \
+ && !OS(ANDROID)
+#define HAVE_TM_GMTOFF 1
+#define HAVE_TM_ZONE 1
+#define HAVE_TIMEGM 1
+#endif
+
+#if OS(DARWIN)
+
+#define HAVE_ERRNO_H 1
+#define HAVE_LANGINFO_H 1
+#define HAVE_MMAP 1
+#define HAVE_MERGESORT 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIMEB_H 1
+#define WTF_USE_ACCELERATE 1
+
+#ifndef TARGETING_LEOPARD
+
+#define HAVE_DISPATCH_H 1
+#define HAVE_HOSTED_CORE_ANIMATION 1
+
+#if !PLATFORM(IOS)
+#define HAVE_MADV_FREE_REUSE 1
+#define HAVE_MADV_FREE 1
+#define HAVE_PTHREAD_SETNAME_NP 1
+#endif
+
+#endif
+
+#if PLATFORM(IOS)
+#define HAVE_MADV_FREE 1
+#define HAVE_PTHREAD_SETNAME_NP 1
+#endif
+
+#elif OS(WINDOWS)
+
+#if OS(WINCE)
+#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
+
+#elif OS(QNX)
+
+#define HAVE_ERRNO_H 1
+#define HAVE_MMAP 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define WTF_USE_PTHREADS 1
+
+#elif OS(ANDROID)
+
+#define HAVE_ERRNO_H 1
+#define HAVE_LANGINFO_H 0
+#define HAVE_NMAP 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+
+#else
+
+/* FIXME: is this actually used or do other platforms generate their own config.h? */
+
+#define HAVE_ERRNO_H 1
+#define HAVE_LANGINFO_H 1
+#define HAVE_MMAP 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 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
+#if !OS(UNIX)
+#define USE_SYSTEM_MALLOC 1
+#endif
+#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)
+#define ENABLE_FAST_MALLOC_MATCH_VALIDATION 0
+#endif
+
+#if !defined(ENABLE_ICONDATABASE)
+#define ENABLE_ICONDATABASE 1
+#endif
+
+#if !defined(ENABLE_SQL_DATABASE)
+#define ENABLE_SQL_DATABASE 1
+#endif
+
+#if !defined(ENABLE_JAVASCRIPT_DEBUGGER)
+#define ENABLE_JAVASCRIPT_DEBUGGER 1
+#endif
+
+#if !defined(ENABLE_FTPDIR)
+#define ENABLE_FTPDIR 1
+#endif
+
+#if !defined(ENABLE_CONTEXT_MENUS)
+#define ENABLE_CONTEXT_MENUS 1
+#endif
+
+#if !defined(ENABLE_DRAG_SUPPORT)
+#define ENABLE_DRAG_SUPPORT 1
+#endif
+
+#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
+#define ENABLE_DATA_TRANSFER_ITEMS 0
+#endif
+
+#if !defined(ENABLE_DASHBOARD_SUPPORT)
+#define ENABLE_DASHBOARD_SUPPORT 0
+#endif
+
+#if !defined(ENABLE_INSPECTOR)
+#define ENABLE_INSPECTOR 1
+#endif
+
+#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
+
+#if !defined(ENABLE_ORIENTATION_EVENTS)
+#define ENABLE_ORIENTATION_EVENTS 0
+#endif
+
+#if !defined(ENABLE_OPCODE_STATS)
+#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_SAMPLING_REGIONS 0
+#define ENABLE_OPCODE_SAMPLING 0
+#define ENABLE_CODEBLOCK_SAMPLING 0
+#if ENABLE(CODEBLOCK_SAMPLING) && !ENABLE(OPCODE_SAMPLING)
+#error "CODEBLOCK_SAMPLING requires OPCODE_SAMPLING"
+#endif
+#if ENABLE(OPCODE_SAMPLING) || ENABLE(SAMPLING_FLAGS) || ENABLE(SAMPLING_REGIONS)
+#define ENABLE_SAMPLING_THREAD 1
+#endif
+
+#if !defined(ENABLE_GEOLOCATION)
+#define ENABLE_GEOLOCATION 0
+#endif
+
+#if !defined(ENABLE_GESTURE_RECOGNIZER)
+#define ENABLE_GESTURE_RECOGNIZER 0
+#endif
+
+#if !defined(ENABLE_VIEWPORT)
+#define ENABLE_VIEWPORT 0
+#endif
+
+#if !defined(ENABLE_NOTIFICATIONS)
+#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
+
+#if !defined(ENABLE_FULLSCREEN_API)
+#define ENABLE_FULLSCREEN_API 0
+#endif
+
+#if !defined(ENABLE_POINTER_LOCK)
+#define ENABLE_POINTER_LOCK 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
+#else
+#define WTF_USE_JSVALUE32_64 1
+#endif
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
+
+#if !defined(ENABLE_REPAINT_THROTTLING)
+#define ENABLE_REPAINT_THROTTLING 0
+#endif
+
+/* Disable the JIT on versions of GCC prior to 4.1 */
+#if !defined(ENABLE_JIT) && COMPILER(GCC) && !GCC_VERSION_AT_LEAST(4, 1, 0)
+#define ENABLE_JIT 0
+#endif
+
+/* JIT is not implemented for Windows 64-bit */
+#if !defined(ENABLE_JIT) && OS(WINDOWS) && CPU(X86_64)
+#define ENABLE_JIT 0
+#endif
+
+/* 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) \
+ && !OS(QNX)
+#define ENABLE_JIT 1
+#endif
+
+#if !defined(ENABLE_DFG_JIT) && ENABLE(JIT)
+/* Enable the DFG JIT on X86 and X86_64. Only tested on Mac and GNU/Linux. */
+#if (CPU(X86) || CPU(X86_64)) && (PLATFORM(MAC) || OS(LINUX))
+#define ENABLE_DFG_JIT 1
+#endif
+/* Enable the DFG JIT on ARMv7. Only tested on iOS. */
+#if CPU(ARM_THUMB2) && PLATFORM(IOS)
+#define ENABLE_DFG_JIT 1
+#endif
+#endif
+
+/* Profiling of types and values used by JIT code. DFG_JIT depends on it, but you
+ can enable it manually with DFG turned off if you want to use it as a standalone
+ profiler. In that case, you probably want to also enable VERBOSE_VALUE_PROFILE
+ below. */
+#if !defined(ENABLE_VALUE_PROFILER) && ENABLE(DFG_JIT)
+#define ENABLE_VALUE_PROFILER 1
+#endif
+
+#if !defined(ENABLE_VERBOSE_VALUE_PROFILE) && ENABLE(VALUE_PROFILER)
+#define ENABLE_VERBOSE_VALUE_PROFILE 0
+#endif
+
+#if !defined(ENABLE_SIMPLE_HEAP_PROFILING)
+#define ENABLE_SIMPLE_HEAP_PROFILING 0
+#endif
+
+/* Counts uses of write barriers using sampling counters. Be sure to also
+ set ENABLE_SAMPLING_COUNTERS to 1. */
+#if !defined(ENABLE_WRITE_BARRIER_PROFILING)
+#define ENABLE_WRITE_BARRIER_PROFILING 0
+#endif
+
+/* Ensure that either the JIT or the interpreter has been enabled. */
+#if !defined(ENABLE_INTERPRETER) && !ENABLE(JIT)
+#define ENABLE_INTERPRETER 1
+#endif
+#if !(ENABLE(JIT) || ENABLE(INTERPRETER))
+#error You have to have at least one execution model enabled to build JSC
+#endif
+
+#if CPU(SH4) && PLATFORM(QT)
+#define ENABLE_JIT 1
+#endif
+
+/* Configure the 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
+
+#if CPU(X86) || CPU(X86_64) || CPU(MIPS)
+#if !defined(ENABLE_JIT_USE_SOFT_MODULO)
+#define ENABLE_JIT_USE_SOFT_MODULO 1
+#endif
+#endif
+
+#if CPU(X86) && COMPILER(MSVC)
+#define JSC_HOST_CALL __fastcall
+#elif CPU(X86) && COMPILER(GCC)
+#define JSC_HOST_CALL __attribute__ ((fastcall))
+#else
+#define JSC_HOST_CALL
+#endif
+
+/* Configure the interpreter */
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
+#define HAVE_COMPUTED_GOTO 1
+#endif
+#if HAVE(COMPUTED_GOTO) && ENABLE(INTERPRETER)
+#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
+#endif
+
+/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc. Results dumped at exit */
+#define ENABLE_REGEXP_TRACING 0
+
+/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
+#if PLATFORM(CHROMIUM)
+#define ENABLE_YARR_JIT 0
+
+#elif ENABLE(JIT) && !defined(ENABLE_YARR_JIT)
+#define ENABLE_YARR_JIT 1
+
+/* Setting this flag compares JIT results with interpreter results. */
+#define ENABLE_YARR_JIT_DEBUG 0
+#endif
+
+#if ENABLE(JIT) || ENABLE(YARR_JIT)
+#define ENABLE_ASSEMBLER 1
+#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) || PLATFORM(IOS)
+#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
+
+#if !defined(ENABLE_SMOOTH_SCROLLING)
+#define ENABLE_SMOOTH_SCROLLING 0
+#endif
+
+#if !defined(ENABLE_WEB_ARCHIVE)
+#define ENABLE_WEB_ARCHIVE 0
+#endif
+
+/* Use the QXmlStreamReader implementation for XMLDocumentParser */
+/* Use the QXmlQuery implementation for XSLTProcessor */
+#if PLATFORM(QT)
+#if !USE(LIBXML2)
+#define WTF_USE_QXMLSTREAM 1
+#define WTF_USE_QXMLQUERY 1
+#endif
+#endif
+
+#if PLATFORM(MAC)
+/* Complex text framework */
+#ifndef 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(MAC) || PLATFORM(IOS) || PLATFORM(QT) || (PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(WIN_CAIRO)) || PLATFORM(EFL)
+#define WTF_USE_ACCELERATED_COMPOSITING 1
+#endif
+
+#if (PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IOS)
+#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
+#endif
+
+#if !ENABLE(NETSCAPE_PLUGIN_API) || (ENABLE(NETSCAPE_PLUGIN_API) && ((OS(UNIX) && (PLATFORM(QT) || PLATFORM(WX))) || PLATFORM(GTK) || PLATFORM(EFL)))
+#define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
+#endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION)
+#define ENABLE_THREADED_SCROLLING 1
+#endif
+
+/* Set up a define for a common error that is intended to cause a build error -- thus the space after Error. */
+#define WTF_PLATFORM_CFNETWORK Error USE_macro_should_be_used_with_CFNETWORK
+
+/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
+#if PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(QT)
+#define WTF_USE_PLATFORM_STRATEGIES 1
+#endif
+
+#if PLATFORM(WIN)
+#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 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 !defined(ENABLE_THREADING_LIBDISPATCH) && HAVE(DISPATCH_H)
+#define ENABLE_THREADING_LIBDISPATCH 1
+#elif !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#elif !defined(THREADING_GENERIC)
+#define ENABLE_THREADING_GENERIC 1
+#endif
+
+#if ENABLE(GLIB_SUPPORT)
+#include "GTypedefs.h"
+#endif
+
+/* FIXME: This define won't be needed once #27551 is fully landed. However,
+ since most ports try to support sub-project independence, adding new headers
+ to WTF causes many ports to break, and so this way we can address the build
+ breakages one port at a time. */
+#define WTF_USE_EXPORT_MACROS 0
+
+#if (PLATFORM(QT) && !OS(DARWIN)) || PLATFORM(GTK) || PLATFORM(EFL)
+#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
+#endif
+
+#if !defined(ENABLE_COMPARE_AND_SWAP) && COMPILER(GCC) && (CPU(X86) || CPU(X86_64) || CPU(ARM_THUMB2))
+#define ENABLE_COMPARE_AND_SWAP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_GC) && (PLATFORM(MAC) || PLATFORM(IOS)) && ENABLE(COMPARE_AND_SWAP)
+#define ENABLE_PARALLEL_GC 1
+#endif
+
+#ifndef NDEBUG
+#ifndef ENABLE_GC_VALIDATION
+#define ENABLE_GC_VALIDATION 1
+#endif
+#endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define WTF_USE_AVFOUNDATION 1
+#endif
+
+#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(EFL) || (PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(WIN_CAIRO)) || PLATFORM(QT)
+#define WTF_USE_REQUEST_ANIMATION_FRAME_TIMER 1
+#endif
+
+#if PLATFORM(MAC)
+#define WTF_USE_REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR 1
+#endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define HAVE_INVERTED_WHEEL_EVENTS 1
+#endif
+
+#if PLATFORM(MAC)
+#define WTF_USE_COREAUDIO 1
+#endif
+
+#if PLATFORM(CHROMIUM)
+#if !defined(WTF_USE_V8)
+#define WTF_USE_V8 1
+#endif
+#endif /* PLATFORM(CHROMIUM) */
+
+#if !defined(WTF_USE_V8)
+#define WTF_USE_V8 0
+#endif /* !defined(WTF_USE_V8) */
+
+/* Using V8 implies not using JSC and vice versa */
+#define WTF_USE_JSC !WTF_USE_V8
+
+
+#endif /* WTF_Platform_h */
diff --git a/Source/JavaScriptCore/wtf/PlatformBlackBerry.cmake b/Source/JavaScriptCore/wtf/PlatformBlackBerry.cmake
new file mode 100644
index 000000000..5f30d0889
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PlatformBlackBerry.cmake
@@ -0,0 +1,12 @@
+LIST(APPEND WTF_SOURCES
+ OSAllocatorPosix.cpp
+ TCSystemAlloc.cpp
+ ThreadIdentifierDataPthreads.cpp
+ ThreadingPthreads.cpp
+ blackberry/MainThreadBlackBerry.cpp
+ unicode/icu/CollatorICU.cpp
+)
+
+LIST(INSERT WTF_INCLUDE_DIRECTORIES 0
+ "${BLACKBERRY_THIRD_PARTY_DIR}/icu"
+)
diff --git a/Source/JavaScriptCore/wtf/PlatformEfl.cmake b/Source/JavaScriptCore/wtf/PlatformEfl.cmake
new file mode 100644
index 000000000..5805c4180
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PlatformEfl.cmake
@@ -0,0 +1,50 @@
+LIST(APPEND WTF_SOURCES
+ efl/MainThreadEfl.cpp
+ efl/OwnPtrEfl.cpp
+
+ OSAllocatorPosix.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}
+ ${ICU_I18N_LIBRARIES}
+ ${ECORE_LIBRARIES}
+ ${ECORE_EVAS_LIBRARIES}
+ ${EVAS_LIBRARIES}
+ ${CMAKE_DL_LIBS}
+)
+
+LIST(APPEND WTF_LINK_FLAGS
+ ${ECORE_LDFLAGS}
+ ${ECORE_EVAS_LDFLAGS}
+ ${EVAS_LDFLAGS}
+)
+
+LIST(APPEND WTF_INCLUDE_DIRECTORIES
+ ${ECORE_INCLUDE_DIRS}
+ ${ECORE_EVAS_INCLUDE_DIRS}
+ ${EVAS_INCLUDE_DIRS}
+ ${ICU_INCLUDE_DIRS}
+ ${JAVASCRIPTCORE_DIR}/wtf/unicode/
+)
diff --git a/Source/JavaScriptCore/wtf/PlatformWinCE.cmake b/Source/JavaScriptCore/wtf/PlatformWinCE.cmake
new file mode 100644
index 000000000..c34c5e5a5
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PlatformWinCE.cmake
@@ -0,0 +1,26 @@
+LIST(APPEND WTF_HEADERS
+ unicode/wince/UnicodeWinCE.h
+
+ ${3RDPARTY_DIR}/ce-compat/ce_time.h
+ ${3RDPARTY_DIR}/ce-compat/ce_unicode.h
+)
+
+LIST(APPEND WTF_SOURCES
+ NullPtr.cpp
+ OSAllocatorWin.cpp
+ ThreadingWin.cpp
+ ThreadSpecificWin.cpp
+
+ unicode/CollatorDefault.cpp
+ unicode/wince/UnicodeWinCE.cpp
+
+ win/MainThreadWin.cpp
+ win/OwnPtrWin.cpp
+
+ ${3RDPARTY_DIR}/ce-compat/ce_time.c
+ ${3RDPARTY_DIR}/ce-compat/ce_unicode.cpp
+)
+
+LIST(APPEND WTF_LIBRARIES
+ mmtimer
+)
diff --git a/Source/JavaScriptCore/wtf/PossiblyNull.h b/Source/JavaScriptCore/wtf/PossiblyNull.h
new file mode 100644
index 000000000..79c4d8200
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/PossiblyNull.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 PossiblyNull_h
+#define PossiblyNull_h
+
+#include "Assertions.h"
+
+namespace WTF {
+
+template <typename T> struct PossiblyNull {
+ PossiblyNull(T data)
+ : m_data(data)
+ {
+ }
+ PossiblyNull(const PossiblyNull<T>& source)
+ : m_data(source.m_data)
+ {
+ source.m_data = 0;
+ }
+ ~PossiblyNull() { ASSERT(!m_data); }
+ bool getValue(T& out) WARN_UNUSED_RETURN;
+private:
+ mutable T m_data;
+};
+
+template <typename T> bool PossiblyNull<T>::getValue(T& out)
+{
+ out = m_data;
+ bool result = !!m_data;
+ m_data = 0;
+ return result;
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/RandomNumber.cpp b/Source/JavaScriptCore/wtf/RandomNumber.cpp
new file mode 100644
index 000000000..06074ed9f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RandomNumber.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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.
+ *
+ * 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 "RandomNumber.h"
+
+#include "CryptographicallyRandomNumber.h"
+#include "RandomNumberSeed.h"
+
+#include <limits>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if USE(MERSENNE_TWISTER_19937)
+extern "C" {
+#include "mt19937ar.c"
+}
+#endif
+
+namespace WTF {
+
+double randomNumber()
+{
+#if USE(OS_RANDOMNESS)
+ uint32_t bits = cryptographicallyRandomNumber();
+ return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
+#else
+ // Without OS_RANDOMNESS, we fall back to other random number generators
+ // that might not be cryptographically secure. Ideally, most ports would
+ // define USE(OS_RANDOMNESS).
+
+#if USE(MERSENNE_TWISTER_19937)
+ return genrand_res53();
+#else
+ uint32_t part1 = rand() & (RAND_MAX - 1);
+ uint32_t part2 = rand() & (RAND_MAX - 1);
+ // rand only provides 31 bits, and the low order bits of that aren't very random
+ // so we take the high 26 bits of part 1, and the high 27 bits of part2.
+ part1 >>= 5; // drop the low 5 bits
+ part2 >>= 4; // drop the low 4 bits
+ uint64_t fullRandom = part1;
+ fullRandom <<= 27;
+ fullRandom |= part2;
+
+ // Mask off the low 53bits
+ fullRandom &= (1LL << 53) - 1;
+ return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53);
+#endif
+#endif
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/RandomNumber.h b/Source/JavaScriptCore/wtf/RandomNumber.h
new file mode 100644
index 000000000..f2e7e8f50
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RandomNumber.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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.
+ *
+ * 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_RandomNumber_h
+#define WTF_RandomNumber_h
+
+namespace WTF {
+
+ // Returns a pseudo-random number in the range [0, 1), attempts to be
+ // cryptographically secure if possible on the target platform
+ double randomNumber();
+
+}
+
+using WTF::randomNumber;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/RandomNumberSeed.h b/Source/JavaScriptCore/wtf/RandomNumberSeed.h
new file mode 100644
index 000000000..b5547becb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RandomNumberSeed.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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.
+ *
+ * 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_RandomNumberSeed_h
+#define WTF_RandomNumberSeed_h
+
+#include <stdlib.h>
+#include <time.h>
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if OS(UNIX)
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#if USE(MERSENNE_TWISTER_19937)
+extern "C" {
+void init_by_array(unsigned long init_key[],int key_length);
+}
+#endif
+
+// Internal JavaScriptCore usage only
+namespace WTF {
+
+inline void initializeRandomNumberGenerator()
+{
+#if OS(DARWIN)
+ // On Darwin we use arc4random which initialises itself.
+#elif OS(WINCE)
+ // initialize rand()
+ srand(GetTickCount());
+#elif COMPILER(MSVC) && defined(_CRT_RAND_S)
+ // On Windows we use rand_s 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;
+ gettimeofday(&time, 0);
+ srandom(static_cast<unsigned>(time.tv_usec * getpid()));
+#else
+ srand(static_cast<unsigned>(time(0)));
+#endif
+
+#if USE(MERSENNE_TWISTER_19937)
+ // use rand() to initialize the Mersenne Twister random number generator.
+ unsigned long initializationBuffer[4];
+ initializationBuffer[0] = (rand() << 16) | rand();
+ initializationBuffer[1] = (rand() << 16) | rand();
+ initializationBuffer[2] = (rand() << 16) | rand();
+ initializationBuffer[3] = (rand() << 16) | rand();
+ init_by_array(initializationBuffer, 4);
+#endif
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/RedBlackTree.h b/Source/JavaScriptCore/wtf/RedBlackTree.h
new file mode 100644
index 000000000..af4e5c88a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RedBlackTree.h
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2010, 2011 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 RedBlackTree_h
+#define RedBlackTree_h
+
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+namespace WTF {
+
+// This implements a red-black tree with the following properties:
+// - The allocation of nodes in the tree is entirely up to the user.
+// - If you are in possession of a pointer to a node, you can delete
+// it from the tree. The tree will subsequently no longer have a
+// reference to this node.
+// - The key type must implement operator< and ==.
+
+template<typename KeyType, typename ValueType>
+class RedBlackTree {
+ WTF_MAKE_NONCOPYABLE(RedBlackTree);
+private:
+ enum Color {
+ Red = 1,
+ Black
+ };
+
+public:
+ class Node {
+ friend class RedBlackTree;
+
+ public:
+ Node(KeyType key, ValueType value)
+ : m_key(key)
+ , m_value(value)
+ {
+ }
+
+ const Node* successor() const
+ {
+ const Node* x = this;
+ if (x->right())
+ return treeMinimum(x->right());
+ const Node* y = x->parent();
+ while (y && x == y->right()) {
+ x = y;
+ y = y->parent();
+ }
+ return y;
+ }
+
+ const Node* predecessor() const
+ {
+ const Node* x = this;
+ if (x->left())
+ return treeMaximum(x->left());
+ const Node* y = x->parent();
+ while (y && x == y->left()) {
+ x = y;
+ y = y->parent();
+ }
+ return y;
+ }
+
+ Node* successor()
+ {
+ return const_cast<Node*>(const_cast<const Node*>(this)->successor());
+ }
+
+ Node* predecessor()
+ {
+ return const_cast<Node*>(const_cast<const Node*>(this)->predecessor());
+ }
+
+ KeyType m_key;
+ ValueType m_value;
+
+ private:
+ void reset()
+ {
+ m_left = 0;
+ m_right = 0;
+ m_parentAndRed = 1; // initialize to red
+ }
+
+ // NOTE: these methods should pack the parent and red into a single
+ // word. But doing so appears to reveal a bug in the compiler.
+ Node* parent() const
+ {
+ return reinterpret_cast<Node*>(m_parentAndRed & ~static_cast<uintptr_t>(1));
+ }
+
+ void setParent(Node* newParent)
+ {
+ m_parentAndRed = reinterpret_cast<uintptr_t>(newParent) | (m_parentAndRed & 1);
+ }
+
+ Node* left() const
+ {
+ return m_left;
+ }
+
+ void setLeft(Node* node)
+ {
+ m_left = node;
+ }
+
+ Node* right() const
+ {
+ return m_right;
+ }
+
+ void setRight(Node* node)
+ {
+ m_right = node;
+ }
+
+ Color color() const
+ {
+ if (m_parentAndRed & 1)
+ return Red;
+ return Black;
+ }
+
+ void setColor(Color value)
+ {
+ if (value == Red)
+ m_parentAndRed |= 1;
+ else
+ m_parentAndRed &= ~static_cast<uintptr_t>(1);
+ }
+
+ Node* m_left;
+ Node* m_right;
+ uintptr_t m_parentAndRed;
+ };
+
+ RedBlackTree()
+ : m_root(0)
+ {
+ }
+
+ void insert(Node* x)
+ {
+ x->reset();
+ treeInsert(x);
+ x->setColor(Red);
+
+ while (x != m_root && x->parent()->color() == Red) {
+ if (x->parent() == x->parent()->parent()->left()) {
+ Node* y = x->parent()->parent()->right();
+ if (y && y->color() == Red) {
+ // Case 1
+ x->parent()->setColor(Black);
+ y->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ x = x->parent()->parent();
+ } else {
+ if (x == x->parent()->right()) {
+ // Case 2
+ x = x->parent();
+ leftRotate(x);
+ }
+ // Case 3
+ x->parent()->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ rightRotate(x->parent()->parent());
+ }
+ } else {
+ // Same as "then" clause with "right" and "left" exchanged.
+ Node* y = x->parent()->parent()->left();
+ if (y && y->color() == Red) {
+ // Case 1
+ x->parent()->setColor(Black);
+ y->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ x = x->parent()->parent();
+ } else {
+ if (x == x->parent()->left()) {
+ // Case 2
+ x = x->parent();
+ rightRotate(x);
+ }
+ // Case 3
+ x->parent()->setColor(Black);
+ x->parent()->parent()->setColor(Red);
+ leftRotate(x->parent()->parent());
+ }
+ }
+ }
+
+ m_root->setColor(Black);
+ }
+
+ Node* remove(Node* z)
+ {
+ ASSERT(z);
+ ASSERT(z->parent() || z == m_root);
+
+ // Y is the node to be unlinked from the tree.
+ Node* y;
+ if (!z->left() || !z->right())
+ y = z;
+ else
+ y = z->successor();
+
+ // Y is guaranteed to be non-null at this point.
+ Node* x;
+ if (y->left())
+ x = y->left();
+ else
+ x = y->right();
+
+ // X is the child of y which might potentially replace y in
+ // the tree. X might be null at this point.
+ Node* xParent;
+ if (x) {
+ x->setParent(y->parent());
+ xParent = x->parent();
+ } else
+ xParent = y->parent();
+ if (!y->parent())
+ m_root = x;
+ else {
+ if (y == y->parent()->left())
+ y->parent()->setLeft(x);
+ else
+ y->parent()->setRight(x);
+ }
+
+ if (y != z) {
+ if (y->color() == Black)
+ removeFixup(x, xParent);
+
+ y->setParent(z->parent());
+ y->setColor(z->color());
+ y->setLeft(z->left());
+ y->setRight(z->right());
+
+ if (z->left())
+ z->left()->setParent(y);
+ if (z->right())
+ z->right()->setParent(y);
+ if (z->parent()) {
+ if (z->parent()->left() == z)
+ z->parent()->setLeft(y);
+ else
+ z->parent()->setRight(y);
+ } else {
+ ASSERT(m_root == z);
+ m_root = y;
+ }
+ } else if (y->color() == Black)
+ removeFixup(x, xParent);
+
+ return z;
+ }
+
+ Node* remove(const KeyType& key)
+ {
+ Node* result = findExact(key);
+ if (!result)
+ return 0;
+ return remove(result);
+ }
+
+ Node* findExact(const KeyType& key) const
+ {
+ for (Node* current = m_root; current;) {
+ if (current->m_key == key)
+ return current;
+ if (key < current->m_key)
+ current = current->left();
+ else
+ current = current->right();
+ }
+ return 0;
+ }
+
+ Node* findLeastGreaterThanOrEqual(const KeyType& key) const
+ {
+ Node* best = 0;
+ for (Node* current = m_root; current;) {
+ if (current->m_key == key)
+ return current;
+ if (current->m_key < key)
+ current = current->right();
+ else {
+ best = current;
+ current = current->left();
+ }
+ }
+ return best;
+ }
+
+ Node* findGreatestLessThanOrEqual(const KeyType& key) const
+ {
+ Node* best = 0;
+ for (Node* current = m_root; current;) {
+ if (current->m_key == key)
+ return current;
+ if (current->m_key > key)
+ current = current->left();
+ else {
+ best = current;
+ current = current->right();
+ }
+ }
+ return best;
+ }
+
+ Node* first() const
+ {
+ if (!m_root)
+ return 0;
+ return treeMinimum(m_root);
+ }
+
+ Node* last() const
+ {
+ if (!m_root)
+ return 0;
+ return treeMaximum(m_root);
+ }
+
+ // This is an O(n) operation.
+ size_t size()
+ {
+ size_t result = 0;
+ for (Node* current = first(); current; current = current->successor())
+ result++;
+ return result;
+ }
+
+ // This is an O(1) operation.
+ bool isEmpty()
+ {
+ return !m_root;
+ }
+
+private:
+ // Finds the minimum element in the sub-tree rooted at the given
+ // node.
+ static Node* treeMinimum(Node* x)
+ {
+ while (x->left())
+ x = x->left();
+ return x;
+ }
+
+ static Node* treeMaximum(Node* x)
+ {
+ while (x->right())
+ x = x->right();
+ return x;
+ }
+
+ static const Node* treeMinimum(const Node* x)
+ {
+ while (x->left())
+ x = x->left();
+ return x;
+ }
+
+ static const Node* treeMaximum(const Node* x)
+ {
+ while (x->right())
+ x = x->right();
+ return x;
+ }
+
+ void treeInsert(Node* z)
+ {
+ ASSERT(!z->left());
+ ASSERT(!z->right());
+ ASSERT(!z->parent());
+ ASSERT(z->color() == Red);
+
+ Node* y = 0;
+ Node* x = m_root;
+ while (x) {
+ y = x;
+ if (z->m_key < x->m_key)
+ x = x->left();
+ else
+ x = x->right();
+ }
+ z->setParent(y);
+ if (!y)
+ m_root = z;
+ else {
+ if (z->m_key < y->m_key)
+ y->setLeft(z);
+ else
+ y->setRight(z);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Red-Black tree operations
+ //
+
+ // Left-rotates the subtree rooted at x.
+ // Returns the new root of the subtree (x's right child).
+ Node* leftRotate(Node* x)
+ {
+ // Set y.
+ Node* y = x->right();
+
+ // Turn y's left subtree into x's right subtree.
+ x->setRight(y->left());
+ if (y->left())
+ y->left()->setParent(x);
+
+ // Link x's parent to y.
+ y->setParent(x->parent());
+ if (!x->parent())
+ m_root = y;
+ else {
+ if (x == x->parent()->left())
+ x->parent()->setLeft(y);
+ else
+ x->parent()->setRight(y);
+ }
+
+ // Put x on y's left.
+ y->setLeft(x);
+ x->setParent(y);
+
+ return y;
+ }
+
+ // Right-rotates the subtree rooted at y.
+ // Returns the new root of the subtree (y's left child).
+ Node* rightRotate(Node* y)
+ {
+ // Set x.
+ Node* x = y->left();
+
+ // Turn x's right subtree into y's left subtree.
+ y->setLeft(x->right());
+ if (x->right())
+ x->right()->setParent(y);
+
+ // Link y's parent to x.
+ x->setParent(y->parent());
+ if (!y->parent())
+ m_root = x;
+ else {
+ if (y == y->parent()->left())
+ y->parent()->setLeft(x);
+ else
+ y->parent()->setRight(x);
+ }
+
+ // Put y on x's right.
+ x->setRight(y);
+ y->setParent(x);
+
+ return x;
+ }
+
+ // Restores the red-black property to the tree after splicing out
+ // a node. Note that x may be null, which is why xParent must be
+ // supplied.
+ void removeFixup(Node* x, Node* xParent)
+ {
+ while (x != m_root && (!x || x->color() == Black)) {
+ if (x == xParent->left()) {
+ // Note: the text points out that w can not be null.
+ // The reason is not obvious from simply looking at
+ // the code; it comes about from the properties of the
+ // red-black tree.
+ Node* w = xParent->right();
+ ASSERT(w); // x's sibling should not be null.
+ if (w->color() == Red) {
+ // Case 1
+ w->setColor(Black);
+ xParent->setColor(Red);
+ leftRotate(xParent);
+ w = xParent->right();
+ }
+ if ((!w->left() || w->left()->color() == Black)
+ && (!w->right() || w->right()->color() == Black)) {
+ // Case 2
+ w->setColor(Red);
+ x = xParent;
+ xParent = x->parent();
+ } else {
+ if (!w->right() || w->right()->color() == Black) {
+ // Case 3
+ w->left()->setColor(Black);
+ w->setColor(Red);
+ rightRotate(w);
+ w = xParent->right();
+ }
+ // Case 4
+ w->setColor(xParent->color());
+ xParent->setColor(Black);
+ if (w->right())
+ w->right()->setColor(Black);
+ leftRotate(xParent);
+ x = m_root;
+ xParent = x->parent();
+ }
+ } else {
+ // Same as "then" clause with "right" and "left"
+ // exchanged.
+
+ // Note: the text points out that w can not be null.
+ // The reason is not obvious from simply looking at
+ // the code; it comes about from the properties of the
+ // red-black tree.
+ Node* w = xParent->left();
+ ASSERT(w); // x's sibling should not be null.
+ if (w->color() == Red) {
+ // Case 1
+ w->setColor(Black);
+ xParent->setColor(Red);
+ rightRotate(xParent);
+ w = xParent->left();
+ }
+ if ((!w->right() || w->right()->color() == Black)
+ && (!w->left() || w->left()->color() == Black)) {
+ // Case 2
+ w->setColor(Red);
+ x = xParent;
+ xParent = x->parent();
+ } else {
+ if (!w->left() || w->left()->color() == Black) {
+ // Case 3
+ w->right()->setColor(Black);
+ w->setColor(Red);
+ leftRotate(w);
+ w = xParent->left();
+ }
+ // Case 4
+ w->setColor(xParent->color());
+ xParent->setColor(Black);
+ if (w->left())
+ w->left()->setColor(Black);
+ rightRotate(xParent);
+ x = m_root;
+ xParent = x->parent();
+ }
+ }
+ }
+ if (x)
+ x->setColor(Black);
+ }
+
+ Node* m_root;
+};
+
+}
+
+#endif
+
diff --git a/Source/JavaScriptCore/wtf/RefCounted.h b/Source/JavaScriptCore/wtf/RefCounted.h
new file mode 100644
index 000000000..51c5dc26e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RefCounted.h
@@ -0,0 +1,234 @@
+/*
+ * 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
+ * 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 RefCounted_h
+#define RefCounted_h
+
+#include "Assertions.h"
+#include "FastAllocBase.h"
+#include "ThreadRestrictionVerifier.h"
+#include "Noncopyable.h"
+#include "OwnPtr.h"
+#include "UnusedParam.h"
+
+namespace WTF {
+
+// This base class holds the non-template methods and attributes.
+// The RefCounted class inherits from it reducing the template bloat
+// generated by the compiler (technique called template hoisting).
+class RefCountedBase {
+public:
+ void ref()
+ {
+#ifndef NDEBUG
+ // Start thread verification as soon as the ref count gets to 2. This
+ // heuristic reflects the fact that items are often created on one thread
+ // and then given to another thread to be used.
+ // FIXME: Make this restriction tigher. Especially as we move to more
+ // common methods for sharing items across threads like CrossThreadCopier.h
+ // We should be able to add a "detachFromThread" method to make this explicit.
+ if (m_refCount == 1)
+ m_verifier.setShared(true);
+#endif
+ // If this assert fires, it either indicates a thread safety issue or
+ // that the verification needs to change. See ThreadRestrictionVerifier for
+ // the different modes.
+ ASSERT(m_verifier.isSafeToUse());
+ ASSERT(!m_deletionHasBegun);
+ ASSERT(!m_adoptionIsRequired);
+ ++m_refCount;
+ }
+
+ bool hasOneRef() const
+ {
+ ASSERT(m_verifier.isSafeToUse());
+ ASSERT(!m_deletionHasBegun);
+ return m_refCount == 1;
+ }
+
+ int refCount() const
+ {
+ ASSERT(m_verifier.isSafeToUse());
+ return m_refCount;
+ }
+
+ void setMutexForVerifier(Mutex&);
+
+#if HAVE(DISPATCH_H)
+ void setDispatchQueueForVerifier(dispatch_queue_t);
+#endif
+
+ // Turns off verification. Use of this method is discouraged (instead extend
+ // ThreadRestrictionVerifier to verify your case).
+ // FIXME: remove this method.
+ void deprecatedTurnOffVerifier()
+ {
+#ifndef NDEBUG
+ m_verifier.turnOffVerification();
+#endif
+ }
+
+ void relaxAdoptionRequirement()
+ {
+#ifndef NDEBUG
+ ASSERT(!m_deletionHasBegun);
+ ASSERT(m_adoptionIsRequired);
+ m_adoptionIsRequired = false;
+#endif
+ }
+
+ // Helper for generating JIT code. Please do not use for non-JIT purposes.
+ const int* addressOfCount() const
+ {
+ return &m_refCount;
+ }
+
+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_verifier.isSafeToUse());
+ ASSERT(!m_deletionHasBegun);
+ ASSERT(!m_adoptionIsRequired);
+
+ ASSERT(m_refCount > 0);
+ if (m_refCount == 1) {
+#ifndef NDEBUG
+ m_deletionHasBegun = true;
+#endif
+ return true;
+ }
+
+ --m_refCount;
+#ifndef NDEBUG
+ // Stop thread verification when the ref goes to 1 because it
+ // is safe to be passed to another thread at this point.
+ if (m_refCount == 1)
+ m_verifier.setShared(false);
+#endif
+ return false;
+ }
+
+#ifndef NDEBUG
+ bool deletionHasBegun() const
+ {
+ return m_deletionHasBegun;
+ }
+#endif
+
+private:
+
+#ifndef NDEBUG
+ friend void adopted(RefCountedBase*);
+#endif
+
+ int m_refCount;
+#ifndef NDEBUG
+ bool m_deletionHasBegun;
+ bool m_adoptionIsRequired;
+ ThreadRestrictionVerifier m_verifier;
+#endif
+};
+
+#ifndef NDEBUG
+
+inline void adopted(RefCountedBase* object)
+{
+ if (!object)
+ return;
+ ASSERT(!object->m_deletionHasBegun);
+ object->m_adoptionIsRequired = false;
+}
+
+#endif
+
+template<typename T> class RefCounted : public RefCountedBase {
+ WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED;
+public:
+ void deref()
+ {
+ if (derefBase())
+ delete static_cast<T*>(this);
+ }
+
+protected:
+ RefCounted() { }
+ ~RefCounted()
+ {
+ }
+};
+
+template<typename T> class RefCountedCustomAllocated : public RefCountedBase {
+ WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated);
+
+public:
+ void deref()
+ {
+ if (derefBase())
+ delete static_cast<T*>(this);
+ }
+
+protected:
+ ~RefCountedCustomAllocated()
+ {
+ }
+};
+
+#ifdef NDEBUG
+inline void RefCountedBase::setMutexForVerifier(Mutex&) { }
+#else
+inline void RefCountedBase::setMutexForVerifier(Mutex& mutex)
+{
+ m_verifier.setMutexMode(mutex);
+}
+#endif
+
+#if HAVE(DISPATCH_H)
+#ifdef NDEBUG
+inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t) { }
+#else
+inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t queue)
+{
+ m_verifier.setDispatchQueueMode(queue);
+}
+#endif // NDEBUG
+#endif // HAVE(DISPATCH_H)
+
+} // namespace WTF
+
+using WTF::RefCounted;
+using WTF::RefCountedCustomAllocated;
+
+#endif // RefCounted_h
diff --git a/Source/JavaScriptCore/wtf/RefCountedLeakCounter.cpp b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.cpp
new file mode 100644
index 000000000..670f2a0ce
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 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 "RefCountedLeakCounter.h"
+
+#include <wtf/HashCountedSet.h>
+
+namespace WTF {
+
+#ifdef NDEBUG
+
+void RefCountedLeakCounter::suppressMessages(const char*) { }
+void RefCountedLeakCounter::cancelMessageSuppression(const char*) { }
+
+RefCountedLeakCounter::RefCountedLeakCounter(const char*) { }
+RefCountedLeakCounter::~RefCountedLeakCounter() { }
+
+void RefCountedLeakCounter::increment() { }
+void RefCountedLeakCounter::decrement() { }
+
+#else
+
+#define LOG_CHANNEL_PREFIX Log
+static WTFLogChannel LogRefCountedLeaks = { 0x00000000, "", WTFLogChannelOn };
+
+typedef HashCountedSet<const char*, PtrHash<const char*> > ReasonSet;
+static ReasonSet* leakMessageSuppressionReasons;
+
+void RefCountedLeakCounter::suppressMessages(const char* reason)
+{
+ if (!leakMessageSuppressionReasons)
+ leakMessageSuppressionReasons = new ReasonSet;
+ leakMessageSuppressionReasons->add(reason);
+}
+
+void RefCountedLeakCounter::cancelMessageSuppression(const char* reason)
+{
+ ASSERT(leakMessageSuppressionReasons);
+ ASSERT(leakMessageSuppressionReasons->contains(reason));
+ leakMessageSuppressionReasons->remove(reason);
+}
+
+RefCountedLeakCounter::RefCountedLeakCounter(const char* description)
+ : m_description(description)
+{
+}
+
+RefCountedLeakCounter::~RefCountedLeakCounter()
+{
+ static bool loggedSuppressionReason;
+ if (m_count) {
+ if (!leakMessageSuppressionReasons || leakMessageSuppressionReasons->isEmpty())
+ LOG(RefCountedLeaks, "LEAK: %u %s", m_count, m_description);
+ else if (!loggedSuppressionReason) {
+ // This logs only one reason. Later we could change it so we log all the reasons.
+ LOG(RefCountedLeaks, "No leak checking done: %s", leakMessageSuppressionReasons->begin()->first);
+ loggedSuppressionReason = true;
+ }
+ }
+}
+
+void RefCountedLeakCounter::increment()
+{
+ atomicIncrement(&m_count);
+}
+
+void RefCountedLeakCounter::decrement()
+{
+ atomicDecrement(&m_count);
+}
+
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h
new file mode 100644
index 000000000..22c7506ac
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RefCountedLeakCounter.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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 RefCountedLeakCounter_h
+#define RefCountedLeakCounter_h
+
+#include "Assertions.h"
+#include "Threading.h"
+
+namespace WTF {
+
+ struct RefCountedLeakCounter {
+ static void suppressMessages(const char*);
+ static void cancelMessageSuppression(const char*);
+
+ explicit RefCountedLeakCounter(const char* description);
+ ~RefCountedLeakCounter();
+
+ void increment();
+ void decrement();
+
+#ifndef NDEBUG
+ private:
+#if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE)
+ int m_count;
+#else
+ volatile int m_count;
+#endif
+ const char* m_description;
+#endif
+ };
+
+} // namespace WTF
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/RefPtr.h b/Source/JavaScriptCore/wtf/RefPtr.h
new file mode 100644
index 000000000..ac94993e3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RefPtr.h
@@ -0,0 +1,232 @@
+/*
+ * 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
+ * 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.
+ *
+ */
+
+// RefPtr and PassRefPtr are documented at http://webkit.org/coding/RefPtr.html
+
+#ifndef WTF_RefPtr_h
+#define WTF_RefPtr_h
+
+#include <algorithm>
+#include "FastAllocBase.h"
+#include "PassRefPtr.h"
+
+namespace WTF {
+
+ enum PlacementNewAdoptType { PlacementNewAdopt };
+
+ template<typename T> class PassRefPtr;
+ template<typename T> class NonNullPassRefPtr;
+
+ enum HashTableDeletedValueType { HashTableDeletedValue };
+
+ template<typename T> class RefPtr {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ 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.
+ 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(); }
+
+ ALWAYS_INLINE ~RefPtr() { derefIfNotNull(m_ptr); }
+
+ T* get() const { return m_ptr; }
+
+ void clear();
+ PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; }
+
+ 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* (RefPtr::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType() const { return m_ptr ? &RefPtr::m_ptr : 0; }
+
+ RefPtr& operator=(const RefPtr&);
+ RefPtr& operator=(T*);
+ RefPtr& operator=(const PassRefPtr<T>&);
+ RefPtr& operator=(const NonNullPassRefPtr<T>&);
+#if !COMPILER_SUPPORTS(CXX_NULLPTR)
+ RefPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+ 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&);
+
+ 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.leakRef())
+ {
+ }
+
+ template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
+ {
+ }
+
+ 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)
+ {
+ T* optr = o.get();
+ refIfNotNull(optr);
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o)
+ {
+ T* optr = o.get();
+ refIfNotNull(optr);
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr)
+ {
+ refIfNotNull(optr);
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
+ {
+ T* ptr = m_ptr;
+ m_ptr = o.leakRef();
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o)
+ {
+ T* ptr = m_ptr;
+ m_ptr = o.leakRef();
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o)
+ {
+ T* ptr = m_ptr;
+ m_ptr = o.leakRef();
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o)
+ {
+ T* ptr = m_ptr;
+ m_ptr = o.leakRef();
+ derefIfNotNull(ptr);
+ return *this;
+ }
+
+ 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)
+ {
+ a.swap(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)
+ {
+ return a.get() == 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)
+ {
+ return a.get() != b.get();
+ }
+
+ 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)
+ {
+ return a != b.get();
+ }
+
+ 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)
+ {
+ return RefPtr<T>(const_cast<T*>(p.get()));
+ }
+
+ template<typename T> inline T* getPtr(const RefPtr<T>& p)
+ {
+ return p.get();
+ }
+
+} // namespace WTF
+
+using WTF::RefPtr;
+using WTF::static_pointer_cast;
+using WTF::const_pointer_cast;
+
+#endif // WTF_RefPtr_h
diff --git a/Source/JavaScriptCore/wtf/RefPtrHashMap.h b/Source/JavaScriptCore/wtf/RefPtrHashMap.h
new file mode 100644
index 000000000..f48a59cf6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RefPtrHashMap.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011 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 RefPtrHashMap_h
+#define RefPtrHashMap_h
+
+namespace WTF {
+
+ // This specialization is a copy of HashMap for use with RefPtr keys, with overloaded functions
+ // to allow for lookup by pointer instead of RefPtr, avoiding ref-count churn.
+
+ // FIXME: Find a way to do this with traits that doesn't require a copy of the HashMap template.
+
+ template<typename T, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
+ class HashMap<RefPtr<T>, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef KeyTraitsArg KeyTraits;
+ typedef MappedTraitsArg MappedTraits;
+ typedef PairHashTraits<KeyTraits, MappedTraits> ValueTraits;
+
+ public:
+ typedef typename KeyTraits::TraitType KeyType;
+ typedef T* RawKeyType;
+ typedef typename MappedTraits::TraitType MappedType;
+ typedef typename ValueTraits::TraitType ValueType;
+
+ private:
+ typedef typename MappedTraits::PassInType MappedPassInType;
+ typedef typename MappedTraits::PassOutType MappedPassOutType;
+ typedef typename MappedTraits::PeekType MappedPeekType;
+
+ typedef typename ReferenceTypeMaker<MappedPassInType>::ReferenceType MappedPassInReferenceType;
+
+ typedef HashArg HashFunctions;
+
+ typedef HashTable<KeyType, ValueType, PairFirstExtractor<ValueType>,
+ HashFunctions, ValueTraits, KeyTraits> HashTableType;
+
+ typedef HashMapTranslator<ValueTraits, HashFunctions>
+ Translator;
+
+ public:
+ typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
+
+ void swap(HashMap&);
+
+ int size() const;
+ int capacity() const;
+ bool isEmpty() const;
+
+ // iterators iterate over pairs of keys and values
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator find(const KeyType&);
+ iterator find(RawKeyType);
+ const_iterator find(const KeyType&) const;
+ const_iterator find(RawKeyType) const;
+ bool contains(const KeyType&) const;
+ bool contains(RawKeyType) const;
+ MappedPeekType get(const KeyType&) const;
+ MappedPeekType get(RawKeyType) const;
+ MappedPeekType inlineGet(RawKeyType) const;
+
+ // replaces value but not key if key is already present
+ // return value is a pair of the iterator to the key location,
+ // and a boolean that's true if a new value was actually added
+ pair<iterator, bool> set(const KeyType&, MappedPassInType);
+ pair<iterator, bool> set(RawKeyType, MappedPassInType);
+
+ // does nothing if key is already present
+ // return value is a pair of the iterator to the key location,
+ // and a boolean that's true if a new value was actually added
+ pair<iterator, bool> add(const KeyType&, MappedPassInType);
+ pair<iterator, bool> add(RawKeyType, MappedPassInType);
+
+ void remove(const KeyType&);
+ void remove(RawKeyType);
+ void remove(iterator);
+ void clear();
+
+ MappedPassOutType take(const KeyType&); // efficient combination of get with remove
+ MappedPassOutType take(RawKeyType); // efficient combination of get with remove
+
+ private:
+ pair<iterator, bool> inlineAdd(const KeyType&, MappedPassInReferenceType);
+ pair<iterator, bool> inlineAdd(RawKeyType, MappedPassInReferenceType);
+
+ HashTableType m_impl;
+ };
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<RefPtr<T>, U, V, W, X>::swap(HashMap& other)
+ {
+ m_impl.swap(other.m_impl);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline int HashMap<RefPtr<T>, U, V, W, X>::size() const
+ {
+ return m_impl.size();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline int HashMap<RefPtr<T>, U, V, W, X>::capacity() const
+ {
+ return m_impl.capacity();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool HashMap<RefPtr<T>, U, V, W, X>::isEmpty() const
+ {
+ return m_impl.isEmpty();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::begin()
+ {
+ return m_impl.begin();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::end()
+ {
+ return m_impl.end();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::begin() const
+ {
+ return m_impl.begin();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::end() const
+ {
+ return m_impl.end();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::find(const KeyType& key)
+ {
+ return m_impl.find(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::find(RawKeyType key)
+ {
+ return m_impl.template find<Translator>(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::find(const KeyType& key) const
+ {
+ return m_impl.find(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::find(RawKeyType key) const
+ {
+ return m_impl.template find<Translator>(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool HashMap<RefPtr<T>, U, V, W, X>::contains(const KeyType& key) const
+ {
+ return m_impl.contains(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline bool HashMap<RefPtr<T>, U, V, W, X>::contains(RawKeyType key) const
+ {
+ return m_impl.template contains<Translator>(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::inlineAdd(const KeyType& key, MappedPassInReferenceType mapped)
+ {
+ return m_impl.template add<Translator>(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::inlineAdd(RawKeyType key, MappedPassInReferenceType mapped)
+ {
+ return m_impl.template add<Translator>(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::set(const KeyType& key, MappedPassInType mapped)
+ {
+ pair<iterator, bool> result = inlineAdd(key, mapped);
+ if (!result.second) {
+ // The inlineAdd call above found an existing hash table entry; we need to set the mapped value.
+ MappedTraits::store(mapped, result.first->second);
+ }
+ return result;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::set(RawKeyType key, MappedPassInType mapped)
+ {
+ pair<iterator, bool> result = inlineAdd(key, mapped);
+ if (!result.second) {
+ // The inlineAdd call above found an existing hash table entry; we need to set the mapped value.
+ MappedTraits::store(mapped, result.first->second);
+ }
+ return result;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::add(const KeyType& key, MappedPassInType mapped)
+ {
+ return inlineAdd(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
+ HashMap<RefPtr<T>, U, V, W, X>::add(RawKeyType key, MappedPassInType mapped)
+ {
+ return inlineAdd(key, mapped);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedPeekType
+ HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(const KeyType& key) const
+ {
+ ValueType* entry = const_cast<HashTableType&>(m_impl).lookup(key);
+ if (!entry)
+ return MappedTraits::peek(MappedTraits::emptyValue());
+ return MappedTraits::peek(entry->second);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedPeekType
+ inline HashMap<RefPtr<T>, U, V, W, MappedTraits>::inlineGet(RawKeyType key) const
+ {
+ ValueType* entry = const_cast<HashTableType&>(m_impl).template lookup<Translator>(key);
+ if (!entry)
+ return MappedTraits::peek(MappedTraits::emptyValue());
+ return MappedTraits::peek(entry->second);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedPeekType
+ HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(RawKeyType key) const
+ {
+ return inlineGet(key);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<RefPtr<T>, U, V, W, X>::remove(iterator it)
+ {
+ if (it.m_impl == m_impl.end())
+ return;
+ m_impl.internalCheckTableConsistency();
+ m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<RefPtr<T>, U, V, W, X>::remove(const KeyType& key)
+ {
+ remove(find(key));
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<RefPtr<T>, U, V, W, X>::remove(RawKeyType key)
+ {
+ remove(find(key));
+ }
+
+ template<typename T, typename U, typename V, typename W, typename X>
+ inline void HashMap<RefPtr<T>, U, V, W, X>::clear()
+ {
+ m_impl.clear();
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedPassOutType
+ HashMap<RefPtr<T>, U, V, W, MappedTraits>::take(const KeyType& key)
+ {
+ iterator it = find(key);
+ if (it == end())
+ return MappedTraits::passOut(MappedTraits::emptyValue());
+ MappedPassOutType result = MappedTraits::passOut(it->second);
+ remove(it);
+ return result;
+ }
+
+ template<typename T, typename U, typename V, typename W, typename MappedTraits>
+ typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedPassOutType
+ HashMap<RefPtr<T>, U, V, W, MappedTraits>::take(RawKeyType key)
+ {
+ iterator it = find(key);
+ if (it == end())
+ return MappedTraits::passOut(MappedTraits::emptyValue());
+ MappedPassOutType result = MappedTraits::passOut(it->second);
+ remove(it);
+ return result;
+ }
+
+} // namespace WTF
+
+#endif // RefPtrHashMap_h
diff --git a/Source/JavaScriptCore/wtf/RetainPtr.h b/Source/JavaScriptCore/wtf/RetainPtr.h
new file mode 100644
index 000000000..3d4b0c3f9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/RetainPtr.h
@@ -0,0 +1,299 @@
+/*
+ * 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
+ * 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 RetainPtr_h
+#define RetainPtr_h
+
+#include "HashTraits.h"
+#include "NullPtr.h"
+#include "TypeTraits.h"
+#include <algorithm>
+
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#endif
+
+namespace WTF {
+
+ // Unlike most most of our smart pointers, RetainPtr can take either the pointer type or the pointed-to type,
+ // so both RetainPtr<NSDictionary> and RetainPtr<CFDictionaryRef> will work.
+
+ enum AdoptCFTag { AdoptCF };
+ enum AdoptNSTag { AdoptNS };
+
+#ifdef __OBJC__
+ inline void adoptNSReference(id ptr)
+ {
+ if (ptr) {
+ CFRetain(ptr);
+ [ptr release];
+ }
+ }
+#endif
+
+ template<typename T> class RetainPtr {
+ public:
+ typedef typename RemovePointer<T>::Type ValueType;
+ typedef ValueType* PtrType;
+
+ RetainPtr() : m_ptr(0) {}
+ RetainPtr(PtrType ptr) : m_ptr(ptr) { if (ptr) CFRetain(ptr); }
+
+ RetainPtr(AdoptCFTag, PtrType ptr) : m_ptr(ptr) { }
+ RetainPtr(AdoptNSTag, PtrType ptr) : m_ptr(ptr) { adoptNSReference(ptr); }
+
+ RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); }
+
+#if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
+ RetainPtr(RetainPtr&& o) : m_ptr(o.leakRef()) { }
+#endif
+
+ // 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>&);
+
+ PtrType get() const { return m_ptr; }
+
+ void clear();
+ PtrType leakRef() WARN_UNUSED_RETURN;
+
+ PtrType 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 PtrType RetainPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; }
+
+ RetainPtr& operator=(const RetainPtr&);
+ template<typename U> RetainPtr& operator=(const RetainPtr<U>&);
+ RetainPtr& operator=(PtrType);
+ template<typename U> RetainPtr& operator=(U*);
+
+#if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
+ RetainPtr& operator=(RetainPtr&&);
+ template<typename U> RetainPtr& operator=(RetainPtr<U>&&);
+#endif
+
+#if !COMPILER_SUPPORTS(CXX_NULLPTR)
+ RetainPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+
+ void adoptCF(PtrType);
+ void adoptNS(PtrType);
+
+ void swap(RetainPtr&);
+
+ private:
+ static PtrType hashTableDeletedValue() { return reinterpret_cast<PtrType>(-1); }
+
+ PtrType m_ptr;
+ };
+
+ 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)
+ CFRetain(optr);
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o)
+ {
+ PtrType optr = o.get();
+ if (optr)
+ CFRetain(optr);
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ return *this;
+ }
+
+ template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr)
+ {
+ if (optr)
+ CFRetain(optr);
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr)
+ {
+ if (optr)
+ CFRetain(optr);
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ return *this;
+ }
+
+#if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
+ template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr<T>&& o)
+ {
+ adoptCF(o.leakRef());
+ return *this;
+ }
+
+ template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(RetainPtr<U>&& o)
+ {
+ adoptCF(o.leakRef());
+ return *this;
+ }
+#endif
+
+ template<typename T> inline void RetainPtr<T>::adoptCF(PtrType optr)
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ }
+
+ template<typename T> inline void RetainPtr<T>::adoptNS(PtrType optr)
+ {
+ adoptNSReference(optr);
+
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ CFRelease(ptr);
+ }
+
+ template<typename T> inline void RetainPtr<T>::swap(RetainPtr<T>& o)
+ {
+ std::swap(m_ptr, o.m_ptr);
+ }
+
+ 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)
+ {
+ return a.get() == b.get();
+ }
+
+ 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)
+ {
+ return a == b.get();
+ }
+
+ 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)
+ {
+ return a.get() != b;
+ }
+
+ template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
+ {
+ return a != b.get();
+ }
+
+ template<typename T> inline RetainPtr<T> adoptCF(T) WARN_UNUSED_RETURN;
+ template<typename T> inline RetainPtr<T> adoptCF(T o)
+ {
+ return RetainPtr<T>(AdoptCF, o);
+ }
+
+ template<typename T> inline RetainPtr<T> adoptNS(T) WARN_UNUSED_RETURN;
+ template<typename T> inline RetainPtr<T> adoptNS(T o)
+ {
+ return RetainPtr<T>(AdoptNS, o);
+ }
+
+ // Helper function for creating a RetainPtr using template argument deduction.
+ template<typename T> inline RetainPtr<T> retainPtr(T) WARN_UNUSED_RETURN;
+ template<typename T> inline RetainPtr<T> retainPtr(T o)
+ {
+ return RetainPtr<T>(o);
+ }
+
+ template<typename P> struct HashTraits<RetainPtr<P> > : SimpleClassHashTraits<RetainPtr<P> > { };
+
+ template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<typename RetainPtr<P>::PtrType> {
+ using PtrHash<typename RetainPtr<P>::PtrType>::hash;
+ static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); }
+ using PtrHash<typename RetainPtr<P>::PtrType>::equal;
+ static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; }
+ static bool equal(typename RetainPtr<P>::PtrType a, const RetainPtr<P>& b) { return a == b; }
+ static bool equal(const RetainPtr<P>& a, typename RetainPtr<P>::PtrType b) { return a == b; }
+ };
+
+ template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; };
+
+} // namespace WTF
+
+using WTF::AdoptCF;
+using WTF::AdoptNS;
+using WTF::adoptCF;
+using WTF::adoptNS;
+using WTF::RetainPtr;
+using WTF::retainPtr;
+
+#endif // WTF_RetainPtr_h
diff --git a/Source/JavaScriptCore/wtf/SHA1.cpp b/Source/JavaScriptCore/wtf/SHA1.cpp
new file mode 100644
index 000000000..e76f6ac38
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SHA1.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// A straightforward SHA-1 implementation based on RFC 3174.
+// http://www.ietf.org/rfc/rfc3174.txt
+// The names of functions and variables (such as "a", "b", and "f") follow notations in RFC 3174.
+
+#include "config.h"
+#include "SHA1.h"
+
+#include "Assertions.h"
+#ifndef NDEBUG
+#include "StringExtras.h"
+#include "text/CString.h"
+#endif
+
+namespace WTF {
+
+#ifdef NDEBUG
+static inline void testSHA1() { }
+#else
+static bool isTestSHA1Done;
+
+static void expectSHA1(CString input, int repeat, CString expected)
+{
+ SHA1 sha1;
+ for (int i = 0; i < repeat; ++i)
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length());
+ Vector<uint8_t, 20> digest;
+ sha1.computeHash(digest);
+ char* buffer = 0;
+ CString actual = CString::newUninitialized(40, buffer);
+ for (size_t i = 0; i < 20; ++i) {
+ snprintf(buffer, 3, "%02X", digest.at(i));
+ buffer += 2;
+ }
+ ASSERT_WITH_MESSAGE(actual == expected, "input: %s, repeat: %d, actual: %s, expected: %s", input.data(), repeat, actual.data(), expected.data());
+}
+
+static void testSHA1()
+{
+ if (isTestSHA1Done)
+ return;
+ isTestSHA1Done = true;
+
+ // Examples taken from sample code in RFC 3174.
+ expectSHA1("abc", 1, "A9993E364706816ABA3E25717850C26C9CD0D89D");
+ expectSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+ expectSHA1("a", 1000000, "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");
+ expectSHA1("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452");
+}
+#endif
+
+static inline uint32_t f(int t, uint32_t b, uint32_t c, uint32_t d)
+{
+ ASSERT(t >= 0 && t < 80);
+ if (t < 20)
+ return (b & c) | ((~b) & d);
+ if (t < 40)
+ return b ^ c ^ d;
+ if (t < 60)
+ return (b & c) | (b & d) | (c & d);
+ return b ^ c ^ d;
+}
+
+static inline uint32_t k(int t)
+{
+ ASSERT(t >= 0 && t < 80);
+ if (t < 20)
+ return 0x5a827999;
+ if (t < 40)
+ return 0x6ed9eba1;
+ if (t < 60)
+ return 0x8f1bbcdc;
+ return 0xca62c1d6;
+}
+
+static inline uint32_t rotateLeft(int n, uint32_t x)
+{
+ ASSERT(n >= 0 && n < 32);
+ return (x << n) | (x >> (32 - n));
+}
+
+SHA1::SHA1()
+{
+ // FIXME: Move unit tests somewhere outside the constructor. See bug 55853.
+ testSHA1();
+ reset();
+}
+
+void SHA1::addBytes(const uint8_t* input, size_t length)
+{
+ while (length--) {
+ ASSERT(m_cursor < 64);
+ m_buffer[m_cursor++] = *input++;
+ ++m_totalBytes;
+ if (m_cursor == 64)
+ processBlock();
+ }
+}
+
+void SHA1::computeHash(Vector<uint8_t, 20>& digest)
+{
+ finalize();
+
+ digest.clear();
+ digest.resize(20);
+ for (size_t i = 0; i < 5; ++i) {
+ // Treat hashValue as a big-endian value.
+ uint32_t hashValue = m_hash[i];
+ for (int j = 0; j < 4; ++j) {
+ digest[4 * i + (3 - j)] = hashValue & 0xFF;
+ hashValue >>= 8;
+ }
+ }
+
+ reset();
+}
+
+void SHA1::finalize()
+{
+ ASSERT(m_cursor < 64);
+ m_buffer[m_cursor++] = 0x80;
+ if (m_cursor > 56) {
+ // Pad out to next block.
+ while (m_cursor < 64)
+ m_buffer[m_cursor++] = 0x00;
+ processBlock();
+ }
+
+ for (size_t i = m_cursor; i < 56; ++i)
+ m_buffer[i] = 0x00;
+
+ // Write the length as a big-endian 64-bit value.
+ uint64_t bits = m_totalBytes * 8;
+ for (int i = 0; i < 8; ++i) {
+ m_buffer[56 + (7 - i)] = bits & 0xFF;
+ bits >>= 8;
+ }
+ m_cursor = 64;
+ processBlock();
+}
+
+void SHA1::processBlock()
+{
+ ASSERT(m_cursor == 64);
+
+ uint32_t w[80] = { 0 };
+ for (int t = 0; t < 16; ++t)
+ w[t] = (m_buffer[t * 4] << 24) | (m_buffer[t * 4 + 1] << 16) | (m_buffer[t * 4 + 2] << 8) | m_buffer[t * 4 + 3];
+ for (int t = 16; t < 80; ++t)
+ w[t] = rotateLeft(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
+
+ uint32_t a = m_hash[0];
+ uint32_t b = m_hash[1];
+ uint32_t c = m_hash[2];
+ uint32_t d = m_hash[3];
+ uint32_t e = m_hash[4];
+
+ for (int t = 0; t < 80; ++t) {
+ uint32_t temp = rotateLeft(5, a) + f(t, b, c, d) + e + w[t] + k(t);
+ e = d;
+ d = c;
+ c = rotateLeft(30, b);
+ b = a;
+ a = temp;
+ }
+
+ m_hash[0] += a;
+ m_hash[1] += b;
+ m_hash[2] += c;
+ m_hash[3] += d;
+ m_hash[4] += e;
+
+ m_cursor = 0;
+}
+
+void SHA1::reset()
+{
+ m_cursor = 0;
+ m_totalBytes = 0;
+ m_hash[0] = 0x67452301;
+ m_hash[1] = 0xefcdab89;
+ m_hash[2] = 0x98badcfe;
+ m_hash[3] = 0x10325476;
+ m_hash[4] = 0xc3d2e1f0;
+
+ // Clear the buffer after use in case it's sensitive.
+ memset(m_buffer, 0, sizeof(m_buffer));
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/SHA1.h b/Source/JavaScriptCore/wtf/SHA1.h
new file mode 100644
index 000000000..dad6dc867
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SHA1.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 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_SHA1_h
+#define WTF_SHA1_h
+
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+class SHA1 {
+public:
+ SHA1();
+
+ void addBytes(const Vector<uint8_t>& input)
+ {
+ addBytes(input.data(), input.size());
+ }
+ void addBytes(const uint8_t* input, size_t length);
+
+ // computeHash has a side effect of resetting the state of the object.
+ void computeHash(Vector<uint8_t, 20>&);
+
+private:
+ void finalize();
+ void processBlock();
+ void reset();
+
+ uint8_t m_buffer[64];
+ size_t m_cursor; // Number of bytes filled in m_buffer (0-64).
+ uint64_t m_totalBytes; // Number of bytes added so far.
+ uint32_t m_hash[5];
+};
+
+} // namespace WTF
+
+using WTF::SHA1;
+
+#endif // WTF_SHA1_h
diff --git a/Source/JavaScriptCore/wtf/SegmentedVector.h b/Source/JavaScriptCore/wtf/SegmentedVector.h
new file mode 100644
index 000000000..cb9a5f3a8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SegmentedVector.h
@@ -0,0 +1,255 @@
+/*
+ * 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 SegmentedVector_h
+#define SegmentedVector_h
+
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+ // An iterator for SegmentedVector. It supports only the pre ++ operator
+ template <typename T, size_t SegmentSize> class SegmentedVector;
+ template <typename T, size_t SegmentSize> class SegmentedVectorIterator {
+ private:
+ friend class SegmentedVector<T, SegmentSize>;
+ public:
+ typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
+
+ ~SegmentedVectorIterator() { }
+
+ T& operator*() const { return m_vector.m_segments.at(m_segment)->at(m_index); }
+ T* operator->() const { return &m_vector.m_segments.at(m_segment)->at(m_index); }
+
+ // Only prefix ++ operator supported
+ Iterator& operator++()
+ {
+ ASSERT(m_index != SegmentSize);
+ ++m_index;
+ if (m_index >= m_vector.m_segments.at(m_segment)->size()) {
+ if (m_segment + 1 < m_vector.m_segments.size()) {
+ ASSERT(m_vector.m_segments.at(m_segment)->size() > 0);
+ ++m_segment;
+ m_index = 0;
+ } else {
+ // Points to the "end" symbol
+ m_segment = 0;
+ m_index = SegmentSize;
+ }
+ }
+ return *this;
+ }
+
+ bool operator==(const Iterator& other) const
+ {
+ return m_index == other.m_index && m_segment == other.m_segment && &m_vector == &other.m_vector;
+ }
+
+ bool operator!=(const Iterator& other) const
+ {
+ return m_index != other.m_index || m_segment != other.m_segment || &m_vector != &other.m_vector;
+ }
+
+ SegmentedVectorIterator& operator=(const SegmentedVectorIterator<T, SegmentSize>& other)
+ {
+ m_vector = other.m_vector;
+ m_segment = other.m_segment;
+ m_index = other.m_index;
+ return *this;
+ }
+
+ private:
+ SegmentedVectorIterator(SegmentedVector<T, SegmentSize>& vector, size_t segment, size_t index)
+ : m_vector(vector)
+ , m_segment(segment)
+ , m_index(index)
+ {
+ }
+
+ SegmentedVector<T, SegmentSize>& m_vector;
+ size_t m_segment;
+ size_t m_index;
+ };
+
+ // SegmentedVector is just like Vector, but it doesn't move the values
+ // stored in its buffer when it grows. Therefore, it is safe to keep
+ // pointers into a SegmentedVector.
+ template <typename T, size_t SegmentSize> class SegmentedVector {
+ friend class SegmentedVectorIterator<T, SegmentSize>;
+ public:
+ typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
+
+ SegmentedVector()
+ : m_size(0)
+ {
+ m_segments.append(&m_inlineSegment);
+ }
+
+ ~SegmentedVector()
+ {
+ deleteAllSegments();
+ }
+
+ size_t size() const { return m_size; }
+ bool isEmpty() const { return !size(); }
+
+ T& at(size_t index)
+ {
+ if (index < SegmentSize)
+ return m_inlineSegment[index];
+ return segmentFor(index)->at(subscriptFor(index));
+ }
+
+ T& operator[](size_t index)
+ {
+ return at(index);
+ }
+
+ T& last()
+ {
+ return at(size() - 1);
+ }
+
+ template <typename U> void append(const U& value)
+ {
+ ++m_size;
+
+ if (m_size <= SegmentSize) {
+ m_inlineSegment.uncheckedAppend(value);
+ return;
+ }
+
+ if (!segmentExistsFor(m_size - 1))
+ m_segments.append(new Segment);
+ segmentFor(m_size - 1)->uncheckedAppend(value);
+ }
+
+ T& alloc()
+ {
+ append<T>(T());
+ return last();
+ }
+
+ void removeLast()
+ {
+ if (m_size <= SegmentSize)
+ m_inlineSegment.removeLast();
+ else
+ segmentFor(m_size - 1)->removeLast();
+ --m_size;
+ }
+
+ void grow(size_t size)
+ {
+ ASSERT(size > m_size);
+ ensureSegmentsFor(size);
+ m_size = size;
+ }
+
+ void clear()
+ {
+ deleteAllSegments();
+ m_segments.resize(1);
+ m_inlineSegment.clear();
+ m_size = 0;
+ }
+
+ Iterator begin()
+ {
+ return Iterator(*this, 0, m_size ? 0 : SegmentSize);
+ }
+
+ Iterator end()
+ {
+ return Iterator(*this, 0, SegmentSize);
+ }
+
+ private:
+ typedef Vector<T, SegmentSize> Segment;
+
+ void deleteAllSegments()
+ {
+ // Skip the first segment, because it's our inline segment, which was
+ // not created by new.
+ for (size_t i = 1; i < m_segments.size(); i++)
+ delete m_segments[i];
+ }
+
+ bool segmentExistsFor(size_t index)
+ {
+ return index / SegmentSize < m_segments.size();
+ }
+
+ Segment* segmentFor(size_t index)
+ {
+ return m_segments[index / SegmentSize];
+ }
+
+ size_t subscriptFor(size_t index)
+ {
+ return index % SegmentSize;
+ }
+
+ void ensureSegmentsFor(size_t size)
+ {
+ size_t segmentCount = m_size / SegmentSize;
+ if (m_size % SegmentSize)
+ ++segmentCount;
+ segmentCount = std::max<size_t>(segmentCount, 1); // We always have at least our inline segment.
+
+ size_t neededSegmentCount = size / SegmentSize;
+ if (size % SegmentSize)
+ ++neededSegmentCount;
+
+ // Fill up to N - 1 segments.
+ size_t end = neededSegmentCount - 1;
+ for (size_t i = segmentCount - 1; i < end; ++i)
+ ensureSegment(i, SegmentSize);
+
+ // Grow segment N to accomodate the remainder.
+ ensureSegment(end, subscriptFor(size - 1) + 1);
+ }
+
+ void ensureSegment(size_t segmentIndex, size_t size)
+ {
+ ASSERT(segmentIndex <= m_segments.size());
+ if (segmentIndex == m_segments.size())
+ m_segments.append(new Segment);
+ m_segments[segmentIndex]->grow(size);
+ }
+
+ size_t m_size;
+ Segment m_inlineSegment;
+ Vector<Segment*, 32> m_segments;
+ };
+
+} // namespace WTF
+
+using WTF::SegmentedVector;
+
+#endif // SegmentedVector_h
diff --git a/Source/JavaScriptCore/wtf/SentinelLinkedList.h b/Source/JavaScriptCore/wtf/SentinelLinkedList.h
new file mode 100644
index 000000000..ecd602452
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SentinelLinkedList.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// A SentinelLinkedList is a linked list with dummy head and tail sentinels,
+// which allow for branch-less insertion and removal, and removal without a
+// pointer to the list.
+//
+// Requires: Node is a concrete class with:
+// Node(SentinelTag);
+// void setPrev(Node*);
+// Node* prev();
+// void setNext(Node*);
+// Node* next();
+
+#ifndef SentinelLinkedList_h
+#define SentinelLinkedList_h
+
+namespace WTF {
+
+enum SentinelTag { Sentinel };
+
+template<typename T>
+class BasicRawSentinelNode {
+public:
+ BasicRawSentinelNode(SentinelTag)
+ : m_next(0)
+ , m_prev(0)
+ {
+ }
+
+ BasicRawSentinelNode()
+ : m_next(0)
+ , m_prev(0)
+ {
+ }
+
+ void setPrev(BasicRawSentinelNode* prev) { m_prev = prev; }
+ void setNext(BasicRawSentinelNode* next) { m_next = next; }
+
+ T* prev() { return static_cast<T*>(m_prev); }
+ T* next() { return static_cast<T*>(m_next); }
+
+ bool isOnList() const
+ {
+ ASSERT(!!m_prev == !!m_next);
+ return !!m_prev;
+ }
+
+ void remove();
+
+private:
+ BasicRawSentinelNode* m_next;
+ BasicRawSentinelNode* m_prev;
+};
+
+template <typename T, typename RawNode = T> class SentinelLinkedList {
+public:
+ typedef T* iterator;
+
+ SentinelLinkedList();
+
+ void push(T*);
+ static void remove(T*);
+
+ iterator begin();
+ iterator end();
+
+private:
+ RawNode m_headSentinel;
+ RawNode m_tailSentinel;
+};
+
+template <typename T> void BasicRawSentinelNode<T>::remove()
+{
+ SentinelLinkedList<T, BasicRawSentinelNode<T> >::remove(static_cast<T*>(this));
+}
+
+template <typename T, typename RawNode> inline SentinelLinkedList<T, RawNode>::SentinelLinkedList()
+ : m_headSentinel(Sentinel)
+ , m_tailSentinel(Sentinel)
+{
+ m_headSentinel.setNext(&m_tailSentinel);
+ m_headSentinel.setPrev(0);
+
+ m_tailSentinel.setPrev(&m_headSentinel);
+ m_tailSentinel.setNext(0);
+}
+
+template <typename T, typename RawNode> inline typename SentinelLinkedList<T, RawNode>::iterator SentinelLinkedList<T, RawNode>::begin()
+{
+ return static_cast<T*>(m_headSentinel.next());
+}
+
+template <typename T, typename RawNode> inline typename SentinelLinkedList<T, RawNode>::iterator SentinelLinkedList<T, RawNode>::end()
+{
+ return static_cast<T*>(&m_tailSentinel);
+}
+
+template <typename T, typename RawNode> inline void SentinelLinkedList<T, RawNode>::push(T* node)
+{
+ ASSERT(node);
+ ASSERT(!node->prev());
+ ASSERT(!node->next());
+
+ RawNode* prev = &m_headSentinel;
+ RawNode* next = m_headSentinel.next();
+
+ node->setPrev(prev);
+ node->setNext(next);
+
+ prev->setNext(node);
+ next->setPrev(node);
+}
+
+template <typename T, typename RawNode> inline void SentinelLinkedList<T, RawNode>::remove(T* node)
+{
+ ASSERT(node);
+ ASSERT(!!node->prev());
+ ASSERT(!!node->next());
+
+ RawNode* prev = node->prev();
+ RawNode* next = node->next();
+
+ prev->setNext(next);
+ next->setPrev(prev);
+
+ node->setPrev(0);
+ node->setNext(0);
+}
+
+}
+
+using WTF::BasicRawSentinelNode;
+using WTF::SentinelLinkedList;
+
+#endif
+
diff --git a/Source/JavaScriptCore/wtf/SinglyLinkedList.h b/Source/JavaScriptCore/wtf/SinglyLinkedList.h
new file mode 100644
index 000000000..c00bf3687
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SinglyLinkedList.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 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 SinglyLinkedList_h
+#define SinglyLinkedList_h
+
+namespace WTF {
+
+template <typename Node> class SinglyLinkedList {
+public:
+ SinglyLinkedList();
+
+ bool isEmpty();
+
+ void push(Node*);
+ Node* pop();
+
+private:
+ Node* m_head;
+};
+
+template <typename Node> inline SinglyLinkedList<Node>::SinglyLinkedList()
+ : m_head(0)
+{
+}
+
+template <typename Node> inline bool SinglyLinkedList<Node>::isEmpty()
+{
+ return !m_head;
+}
+
+template <typename Node> inline void SinglyLinkedList<Node>::push(Node* node)
+{
+ ASSERT(node);
+ node->setNext(m_head);
+ m_head = node;
+}
+
+template <typename Node> inline Node* SinglyLinkedList<Node>::pop()
+{
+ Node* tmp = m_head;
+ m_head = m_head->next();
+ return tmp;
+}
+
+}
+
+using WTF::SinglyLinkedList;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/SizeLimits.cpp b/Source/JavaScriptCore/wtf/SizeLimits.cpp
new file mode 100644
index 000000000..95d9c2b1e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/SizeLimits.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/ThreadRestrictionVerifier.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+#ifndef NDEBUG
+struct SameSizeAsRefCounted {
+ int a;
+ bool b;
+ bool c;
+ ThreadRestrictionVerifier d;
+ // The debug version may get bigger.
+};
+#else
+struct SameSizeAsRefCounted {
+ int a;
+ // Don't add anything here because this should stay small.
+};
+#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(SameSizeAsRefCounted), RefCounted_should_stay_small);
+COMPILE_ASSERT(sizeof(RefCountedCustomAllocated<int>) == sizeof(SameSizeAsRefCounted), 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/Source/JavaScriptCore/wtf/Spectrum.h b/Source/JavaScriptCore/wtf/Spectrum.h
new file mode 100644
index 000000000..c403eda18
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Spectrum.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 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 Spectrum_h
+#define Spectrum_h
+
+#include "HashMap.h"
+#include "Vector.h"
+#include <algorithm>
+
+namespace WTF {
+
+template<typename T>
+class Spectrum {
+public:
+ typedef typename HashMap<T, unsigned long>::iterator iterator;
+ typedef typename HashMap<T, unsigned long>::const_iterator const_iterator;
+
+ Spectrum() { }
+
+ void add(const T& key, unsigned long count = 1)
+ {
+ std::pair<iterator, bool> result = m_map.add(key, count);
+ if (!result.second)
+ result.first->second += count;
+ }
+
+ unsigned long get(const T& key) const
+ {
+ const_iterator iter = m_map.find(key);
+ if (iter == m_map.end())
+ return 0;
+ return iter->second;
+ }
+
+ iterator begin() { return m_map.begin(); }
+ iterator end() { return m_map.end(); }
+ const_iterator begin() const { return m_map.begin(); }
+ const_iterator end() const { return m_map.end(); }
+
+ struct KeyAndCount {
+ KeyAndCount() { }
+
+ KeyAndCount(const T& key, unsigned long count)
+ : key(key)
+ , count(count)
+ {
+ }
+
+ bool operator<(const KeyAndCount& other) const
+ {
+ if (count != other.count)
+ return count < other.count;
+ // This causes lower-ordered keys being returned first; this is really just
+ // here to make sure that the order is somewhat deterministic rather than being
+ // determined by hashing.
+ return key > other.key;
+ }
+
+ T key;
+ unsigned long count;
+ };
+
+ // Returns a list ordered from lowest-count to highest-count.
+ Vector<KeyAndCount> buildList() const
+ {
+ Vector<KeyAndCount> list;
+ for (const_iterator iter = begin(); iter != end(); ++iter)
+ list.append(KeyAndCount(iter->first, iter->second));
+
+ std::sort(list.begin(), list.end());
+ return list;
+ }
+
+private:
+ HashMap<T, unsigned long> m_map;
+};
+
+} // namespace WTF
+
+using WTF::Spectrum;
+
+#endif // Spectrum_h
diff --git a/Source/JavaScriptCore/wtf/StackBounds.cpp b/Source/JavaScriptCore/wtf/StackBounds.cpp
new file mode 100644
index 000000000..a272ce3de
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StackBounds.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * 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
+ *
+ */
+
+#include "config.h"
+#include "StackBounds.h"
+
+#if OS(DARWIN)
+
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <pthread.h>
+
+#elif OS(WINDOWS)
+
+#include <windows.h>
+
+#elif OS(SOLARIS)
+
+#include <thread.h>
+
+#elif OS(QNX)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/procfs.h>
+
+#elif OS(UNIX)
+
+#include <pthread.h>
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#endif
+
+namespace WTF {
+
+// Bug 26276 - Need a mechanism to determine stack extent
+//
+// These platforms should now be working correctly:
+// DARWIN, QNX, UNIX
+// These platforms are not:
+// WINDOWS, SOLARIS, OPENBSD, WINCE
+//
+// FIXME: remove this! - this code unsafely guesses at stack sizes!
+#if OS(WINDOWS) || OS(SOLARIS) || OS(OPENBSD)
+// Based on the current limit used by the JSC parser, guess the stack size.
+static const ptrdiff_t estimatedStackSize = 128 * sizeof(void*) * 1024;
+// This method assumes the stack is growing downwards.
+static void* estimateStackBound(void* origin)
+{
+ return static_cast<char*>(origin) - estimatedStackSize;
+}
+#endif
+
+#if OS(DARWIN)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ m_origin = pthread_get_stackaddr_np(thread);
+ m_bound = static_cast<char*>(m_origin) - pthread_get_stacksize_np(thread);
+}
+
+#elif OS(QNX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+
+ struct _debug_thread_info threadInfo;
+ memset(&threadInfo, 0, sizeof(threadInfo));
+ threadInfo.tid = pthread_self();
+ int fd = open("/proc/self", O_RDONLY);
+ if (fd == -1) {
+ LOG_ERROR("Unable to open /proc/self (errno: %d)", errno);
+ CRASH();
+ }
+ devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0);
+ close(fd);
+ stackBase = reinterpret_cast<void*>(threadInfo.stkbase);
+ stackSize = threadInfo.stksize;
+ ASSERT(stackBase);
+
+ m_bound = static_cast<char*>(stackBase) + 0x1000; // 4kb guard page
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(SOLARIS)
+
+void StackBounds::initialize()
+{
+ stack_t s;
+ thr_stksegment(&s);
+ m_origin = s.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(OPENBSD)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ stack_t stack;
+ pthread_stackseg_np(thread, &stack);
+ m_origin = stack.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(UNIX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
+ // e.g. on FreeBSD 5.4, neundorf@kde.org
+ pthread_attr_get_np(thread, &sattr);
+#else
+ // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+ pthread_getattr_np(thread, &sattr);
+#endif
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
+ ASSERT(stackBase);
+ pthread_attr_destroy(&sattr);
+ m_bound = stackBase;
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(WINCE)
+
+static bool detectGrowingDownward(void* previousFrame)
+{
+ // Find the address of this stack frame by taking the address of a local variable.
+ int thisFrame;
+ return previousFrame > &thisFrame;
+}
+
+static inline bool isPageWritable(void* page)
+{
+ MEMORY_BASIC_INFORMATION memoryInformation;
+ DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
+
+ // return false on error, including ptr outside memory
+ if (result != sizeof(memoryInformation))
+ return false;
+
+ DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
+ return protect == PAGE_READWRITE
+ || protect == PAGE_WRITECOPY
+ || protect == PAGE_EXECUTE_READWRITE
+ || protect == PAGE_EXECUTE_WRITECOPY;
+}
+
+static inline void* getLowerStackBound(char* currentPage, DWORD pageSize)
+{
+ while (currentPage > 0) {
+ // check for underflow
+ if (currentPage >= reinterpret_cast<char*>(pageSize))
+ currentPage -= pageSize;
+ else
+ currentPage = 0;
+
+ if (!isPageWritable(currentPage))
+ return currentPage + pageSize;
+ }
+
+ return 0;
+}
+
+static inline void* getUpperStackBound(char* currentPage, DWORD pageSize)
+{
+ do {
+ // guaranteed to complete because isPageWritable returns false at end of memory
+ currentPage += pageSize;
+ } while (isPageWritable(currentPage));
+
+ return currentPage - pageSize;
+}
+
+void StackBounds::initialize()
+{
+ // find the address of this stack frame by taking the address of a local variable
+ void* thisFrame = &thisFrame;
+ bool isGrowingDownward = detectGrowingDownward(thisFrame);
+
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ DWORD pageSize = systemInfo.dwPageSize;
+
+ // scan all of memory starting from this frame, and return the last writeable page found
+ char* currentPage = reinterpret_cast<char*>(reinterpret_cast<DWORD>(thisFrame) & ~(pageSize - 1));
+ void* lowerStackBound = getLowerStackBound(currentPage, pageSize);
+ void* upperStackBound = getUpperStackBound(currentPage, pageSize);
+
+ m_origin = isGrowingDownward ? upperStackBound : lowerStackBound;
+ m_bound = isGrowingDownward ? lowerStackBound : upperStackBound;
+}
+
+#elif OS(WINDOWS)
+
+void StackBounds::initialize()
+{
+#if CPU(X86) && COMPILER(MSVC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ __asm {
+ MOV EAX, FS:[18h]
+ MOV pTib, EAX
+ }
+ m_origin = static_cast<void*>(pTib->StackBase);
+#elif CPU(X86) && COMPILER(GCC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ asm ( "movl %%fs:0x18, %0\n"
+ : "=r" (pTib)
+ );
+ m_origin = static_cast<void*>(pTib->StackBase);
+#elif CPU(X86_64)
+ PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+ m_origin = reinterpret_cast<void*>(pTib->StackBase);
+#else
+#error Need a way to get the stack bounds on this platform (Windows)
+#endif
+ // Looks like we should be able to get pTib->StackLimit
+ m_bound = estimateStackBound(m_origin);
+}
+
+#else
+#error Need a way to get the stack bounds on this platform
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/StackBounds.h b/Source/JavaScriptCore/wtf/StackBounds.h
new file mode 100644
index 000000000..afce8606f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StackBounds.h
@@ -0,0 +1,114 @@
+/*
+ * 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 StackBounds_h
+#define StackBounds_h
+
+namespace WTF {
+
+class StackBounds {
+ // recursionCheck() / recursionLimit() tests (by default)
+ // that we are at least this far from the end of the stack.
+ const static size_t s_defaultAvailabilityDelta = 4096;
+
+public:
+ StackBounds()
+ : m_origin(0)
+ , m_bound(0)
+ {
+ }
+
+ static StackBounds currentThreadStackBounds()
+ {
+ StackBounds bounds;
+ bounds.initialize();
+ bounds.checkConsistency();
+ return bounds;
+ }
+
+ void* origin() const
+ {
+ ASSERT(m_origin);
+ return m_origin;
+ }
+
+ void* current() const
+ {
+ checkConsistency();
+ void* currentPosition = &currentPosition;
+ return currentPosition;
+ }
+
+ void* recursionLimit(size_t minAvailableDelta = s_defaultAvailabilityDelta) const
+ {
+ checkConsistency();
+ return isGrowingDownward()
+ ? static_cast<char*>(m_bound) + minAvailableDelta
+ : static_cast<char*>(m_bound) - minAvailableDelta;
+ }
+
+ bool recursionCheck(size_t minAvailableDelta = s_defaultAvailabilityDelta) const
+ {
+ checkConsistency();
+ return isGrowingDownward()
+ ? current() >= recursionLimit(minAvailableDelta)
+ : current() <= recursionLimit(minAvailableDelta);
+ }
+
+private:
+ void initialize();
+
+
+ bool isGrowingDownward() const
+ {
+ ASSERT(m_origin && m_bound);
+#if OS(WINCE)
+ return m_origin > m_bound;
+#else
+ return true;
+#endif
+ }
+
+ void checkConsistency() const
+ {
+#if !ASSERT_DISABLED
+ void* currentPosition = &currentPosition;
+ ASSERT(m_origin != m_bound);
+ ASSERT(isGrowingDownward()
+ ? (currentPosition < m_origin && currentPosition > m_bound)
+ : (currentPosition > m_origin && currentPosition < m_bound));
+#endif
+ }
+
+ void* m_origin;
+ void* m_bound;
+};
+
+} // namespace WTF
+
+using WTF::StackBounds;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/StaticConstructors.h b/Source/JavaScriptCore/wtf/StaticConstructors.h
new file mode 100644
index 000000000..702c0ca5c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StaticConstructors.h
@@ -0,0 +1,74 @@
+/*
+ * 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;
+#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 *)];
+#else
+#define DEFINE_GLOBAL(type, name, ...) \
+ void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)];
+#endif
+#endif
+
+#endif // StaticConstructors_h
diff --git a/Source/JavaScriptCore/wtf/StdLibExtras.h b/Source/JavaScriptCore/wtf/StdLibExtras.h
new file mode 100644
index 000000000..3f99c4d3f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StdLibExtras.h
@@ -0,0 +1,290 @@
+/*
+ * 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 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_StdLibExtras_h
+#define WTF_StdLibExtras_h
+
+#include "CheckedArithmetic.h"
+#include "Assertions.h"
+
+// Use these to declare and define a static local variable (static T;) so that
+// it is leaked so that its destructors are not called at exit. Using this
+// macro also allows workarounds a compiler bug present in Apple's version of GCC 4.0.1.
+#ifndef DEFINE_STATIC_LOCAL
+#if COMPILER(GCC) && defined(__APPLE_CC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 1
+#define DEFINE_STATIC_LOCAL(type, name, arguments) \
+ static type* name##Ptr = new type arguments; \
+ type& name = *name##Ptr
+#else
+#define DEFINE_STATIC_LOCAL(type, name, arguments) \
+ static type& name = *new type arguments
+#endif
+#endif
+
+// Use this macro to declare and define a debug-only global variable that may have a
+// non-trivial constructor and destructor. When building with clang, this will suppress
+// warnings about global constructors and exit-time destructors.
+#ifndef NDEBUG
+#if COMPILER(CLANG)
+#define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
+ _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
+ static type name arguments; \
+ _Pragma("clang diagnostic pop")
+#else
+#define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) \
+ static type name arguments;
+#endif // COMPILER(CLANG)
+#else
+#define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments)
+#endif // NDEBUG
+
+// OBJECT_OFFSETOF: Like the C++ offsetof macro, but you can use it with classes.
+// The magic number 0x4000 is insignificant. We use it to avoid using NULL, since
+// NULL can cause compiler problems, especially in cases of multiple inheritance.
+#define OBJECT_OFFSETOF(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000)
+
+// STRINGIZE: Can convert any value to quoted string, even expandable macros
+#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>
+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;
+}
+
+template<typename To, typename From>
+inline To safeCast(From value)
+{
+ ASSERT(isInBounds<To>(value));
+ return static_cast<To>(value);
+}
+
+// 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))
+
+// Efficient implementation that takes advantage of powers of two.
+template<size_t divisor> inline size_t roundUpToMultipleOf(size_t x)
+{
+ COMPILE_ASSERT(divisor && !(divisor & (divisor - 1)), divisor_is_a_power_of_two);
+
+ size_t remainderMask = divisor - 1;
+ return (x + remainderMask) & ~remainderMask;
+}
+
+enum BinarySearchMode {
+ KeyMustBePresentInArray,
+ KeyMustNotBePresentInArray
+};
+
+// Binary search algorithm, calls extractKey on pre-sorted elements in array,
+// compares result with key (KeyTypes should be comparable with '--', '<', '>').
+template<typename ArrayElementType, typename KeyType, KeyType(*extractKey)(ArrayElementType*)>
+inline ArrayElementType* binarySearch(ArrayElementType* array, size_t size, KeyType key, BinarySearchMode mode = KeyMustBePresentInArray)
+{
+ // The array must contain at least one element (pre-condition, array does contain key).
+ // If the array contains only one element, no need to do the comparison.
+ while (size > 1) {
+ // Pick an element to check, half way through the array, and read the value.
+ int pos = (size - 1) >> 1;
+ KeyType val = extractKey(&array[pos]);
+
+ // If the key matches, success!
+ if (val == key)
+ return &array[pos];
+ // The item we are looking for is smaller than the item being check; reduce the value of 'size',
+ // chopping off the right hand half of the array.
+ else if (key < val)
+ size = pos;
+ // Discard all values in the left hand half of the array, up to and including the item at pos.
+ else {
+ size -= (pos + 1);
+ array += (pos + 1);
+ }
+
+ // In case of BinarySearchMode = KeyMustBePresentInArray 'size' should never reach zero.
+ if (mode == KeyMustBePresentInArray)
+ ASSERT(size);
+ }
+
+ // In case of BinarySearchMode = KeyMustBePresentInArray if we reach this point
+ // we've chopped down to one element, no need to check it matches
+ if (mode == KeyMustBePresentInArray) {
+ ASSERT(size == 1);
+ ASSERT(key == extractKey(&array[0]));
+ }
+
+ return &array[0];
+}
+
+// Modified binary search algorithm that uses a functor. Note that this is strictly
+// more powerful than the above, but results in somewhat less template specialization.
+// Hence, depending on inlining heuristics, it might be slower.
+template<typename ArrayElementType, typename KeyType, typename ExtractKey>
+inline ArrayElementType* binarySearchWithFunctor(ArrayElementType* array, size_t size, KeyType key, BinarySearchMode mode = KeyMustBePresentInArray, const ExtractKey& extractKey = ExtractKey())
+{
+ // The array must contain at least one element (pre-condition, array does contain key).
+ // If the array contains only one element, no need to do the comparison.
+ while (size > 1) {
+ // Pick an element to check, half way through the array, and read the value.
+ int pos = (size - 1) >> 1;
+ KeyType val = extractKey(&array[pos]);
+
+ // If the key matches, success!
+ if (val == key)
+ return &array[pos];
+ // The item we are looking for is smaller than the item being check; reduce the value of 'size',
+ // chopping off the right hand half of the array.
+ else if (key < val)
+ size = pos;
+ // Discard all values in the left hand half of the array, up to and including the item at pos.
+ else {
+ size -= (pos + 1);
+ array += (pos + 1);
+ }
+
+ // In case of BinarySearchMode = KeyMustBePresentInArray 'size' should never reach zero.
+ if (mode == KeyMustBePresentInArray)
+ ASSERT(size);
+ }
+
+ // In case of BinarySearchMode = KeyMustBePresentInArray if we reach this point
+ // we've chopped down to one element, no need to check it matches
+ if (mode == KeyMustBePresentInArray) {
+ ASSERT(size == 1);
+ ASSERT(key == extractKey(&array[0]));
+ }
+
+ return &array[0];
+}
+
+// Modified binarySearch() algorithm designed for array-like classes that support
+// operator[] but not operator+=. One example of a class that qualifies is
+// SegmentedVector.
+template<typename ArrayElementType, typename KeyType, KeyType(*extractKey)(ArrayElementType*), typename ArrayType>
+inline ArrayElementType* genericBinarySearch(ArrayType& array, size_t size, KeyType key)
+{
+ // The array must contain at least one element (pre-condition, array does conatin key).
+ // If the array only contains one element, no need to do the comparison.
+ size_t offset = 0;
+ while (size > 1) {
+ // Pick an element to check, half way through the array, and read the value.
+ int pos = (size - 1) >> 1;
+ KeyType val = extractKey(&array[offset + pos]);
+
+ // If the key matches, success!
+ if (val == key)
+ return &array[offset + pos];
+ // The item we are looking for is smaller than the item being check; reduce the value of 'size',
+ // chopping off the right hand half of the array.
+ if (key < val)
+ size = pos;
+ // Discard all values in the left hand half of the array, up to and including the item at pos.
+ else {
+ size -= (pos + 1);
+ offset += (pos + 1);
+ }
+
+ // 'size' should never reach zero.
+ ASSERT(size);
+ }
+
+ // If we reach this point we've chopped down to one element, no need to check it matches
+ ASSERT(size == 1);
+ ASSERT(key == extractKey(&array[offset]));
+ return &array[offset];
+}
+
+} // namespace WTF
+
+// This version of placement new omits a 0 check.
+enum NotNullTag { NotNull };
+inline void* operator new(size_t, NotNullTag, void* location)
+{
+ ASSERT(location);
+ return location;
+}
+
+using WTF::binarySearch;
+using WTF::bitwise_cast;
+using WTF::safeCast;
+
+#endif // WTF_StdLibExtras_h
diff --git a/Source/JavaScriptCore/wtf/StringExtras.cpp b/Source/JavaScriptCore/wtf/StringExtras.cpp
new file mode 100644
index 000000000..1b96417c8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StringExtras.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ * 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"
+
+#if COMPILER(RVCT) && __ARMCC_VERSION < 400000
+
+#include "StringExtras.h"
+
+#include "ASCIICType.h"
+
+int strcasecmp(const char* s1, const char* s2)
+{
+ while (toASCIIUpper(*s1) == toASCIIUpper(*s2)) {
+ if (*s1 == '\0')
+ return 0;
+ s1++;
+ s2++;
+ }
+
+ return toASCIIUpper(*s1) - toASCIIUpper(*s2);
+}
+
+int strncasecmp(const char* s1, const char* s2, size_t len)
+{
+ while (len > 0 && toASCIIUpper(*s1) == toASCIIUpper(*s2)) {
+ if (*s1 == '\0')
+ return 0;
+ s1++;
+ s2++;
+ len--;
+ }
+
+ if (!len)
+ return 0;
+
+ return toASCIIUpper(*s1) - toASCIIUpper(*s2);
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/StringExtras.h b/Source/JavaScriptCore/wtf/StringExtras.h
new file mode 100644
index 000000000..371e33bf9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StringExtras.h
@@ -0,0 +1,126 @@
+/*
+ * 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
+ * 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_StringExtras_h
+#define WTF_StringExtras_h
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE(STRINGS_H)
+#include <strings.h>
+#endif
+
+#if COMPILER(MSVC)
+// FIXME: why a COMPILER check instead of OS? also, these should be HAVE checks
+
+inline int snprintf(char* buffer, size_t count, const char* format, ...)
+{
+ int result;
+ va_list args;
+ 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;
+}
+
+inline double wtf_vsnprintf(char* buffer, size_t count, const char* format, va_list 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;
+}
+
+// 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)
+
+inline int strnicmp(const char* string1, const char* string2, size_t count)
+{
+ return _strnicmp(string1, string2, count);
+}
+
+inline int stricmp(const char* string1, const char* string2)
+{
+ return _stricmp(string1, string2);
+}
+
+inline char* strdup(const char* strSource)
+{
+ return _strdup(strSource);
+}
+
+#endif
+
+inline int strncasecmp(const char* s1, const char* s2, size_t len)
+{
+ return _strnicmp(s1, s2, len);
+}
+
+inline int strcasecmp(const char* s1, const char* s2)
+{
+ return _stricmp(s1, s2);
+}
+
+#endif
+
+#if !HAVE(STRNSTR)
+
+inline char* strnstr(const char* buffer, const char* target, size_t bufferLength)
+{
+ size_t targetLength = strlen(target);
+ if (targetLength == 0)
+ return const_cast<char*>(buffer);
+ for (const char* start = buffer; *start && start + targetLength <= buffer + bufferLength; start++) {
+ if (*start == *target && strncmp(start + 1, target + 1, targetLength - 1) == 0)
+ return const_cast<char*>(start);
+ }
+ return 0;
+}
+
+#endif
+
+#if COMPILER(RVCT) && __ARMCC_VERSION < 400000
+
+int strcasecmp(const char* s1, const char* s2);
+int strncasecmp(const char* s1, const char* s2, size_t len);
+
+#endif
+
+#endif // WTF_StringExtras_h
diff --git a/Source/JavaScriptCore/wtf/StringHasher.h b/Source/JavaScriptCore/wtf/StringHasher.h
new file mode 100644
index 000000000..714525188
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StringHasher.h
@@ -0,0 +1,185 @@
+/*
+ * 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).
+
+// NOTE: This class must stay in sync with the create_hash_table script in
+// JavaScriptCore and the CodeGeneratorJS.pm script in WebCore.
+class StringHasher {
+public:
+ static const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
+
+ 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;
+
+ // Reserving space from the high bits for flags preserves most of the hash's
+ // value, since hash lookup typically masks out the high bits anyway.
+ result &= (1u << (sizeof(result) * 8 - flagCount)) - 1;
+
+ // This avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet". Setting the high bit maintains
+ // reasonable fidelity to a hash code of 0 because it is likely to yield
+ // exactly 0 when hash lookup masks out the high bits.
+ if (!result)
+ result = 0x80000000 >> flagCount;
+
+ return result;
+ }
+
+ template<typename T, UChar Converter(T)> static inline unsigned computeHash(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 computeHash(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 computeHash(const T* data, unsigned length)
+ {
+ return computeHash<T, defaultConverter>(data, length);
+ }
+
+ template<typename T> static inline unsigned computeHash(const T* data)
+ {
+ return computeHash<T, defaultConverter>(data);
+ }
+
+ template<size_t length> static inline unsigned hashMemory(const void* data)
+ {
+ COMPILE_ASSERT(!(length % 4), length_must_be_a_multible_of_four);
+ return computeHash<UChar>(static_cast<const UChar*>(data), length / sizeof(UChar));
+ }
+
+ static inline unsigned hashMemory(const void* data, unsigned size)
+ {
+ ASSERT(!(size % 2));
+ return computeHash<UChar>(static_cast<const UChar*>(data), size / sizeof(UChar));
+ }
+
+private:
+ static inline UChar defaultConverter(UChar ch)
+ {
+ return ch;
+ }
+
+ static inline UChar defaultConverter(LChar ch)
+ {
+ return 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
+
+using WTF::StringHasher;
+
+#endif // WTF_StringHasher_h
diff --git a/Source/JavaScriptCore/wtf/TCPackedCache.h b/Source/JavaScriptCore/wtf/TCPackedCache.h
new file mode 100644
index 000000000..0464f8fdc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TCPackedCache.h
@@ -0,0 +1,234 @@
+// Copyright (c) 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.
+
+// ---
+// Author: Geoff Pike
+//
+// This file provides a minimal cache that can hold a <key, value> pair
+// with little if any wasted space. The types of the key and value
+// must be unsigned integral types or at least have unsigned semantics
+// for >>, casting, and similar operations.
+//
+// Synchronization is not provided. However, the cache is implemented
+// as an array of cache entries whose type is chosen at compile time.
+// If a[i] is atomic on your hardware for the chosen array type then
+// raciness will not necessarily lead to bugginess. The cache entries
+// must be large enough to hold a partial key and a value packed
+// together. The partial keys are bit strings of length
+// kKeybits - kHashbits, and the values are bit strings of length kValuebits.
+//
+// In an effort to use minimal space, every cache entry represents
+// some <key, value> pair; the class provides no way to mark a cache
+// entry as empty or uninitialized. In practice, you may want to have
+// reserved keys or values to get around this limitation. For example, in
+// tcmalloc's PageID-to-sizeclass cache, a value of 0 is used as
+// "unknown sizeclass."
+//
+// Usage Considerations
+// --------------------
+//
+// kHashbits controls the size of the cache. The best value for
+// kHashbits will of course depend on the application. Perhaps try
+// tuning the value of kHashbits by measuring different values on your
+// favorite benchmark. Also remember not to be a pig; other
+// programs that need resources may suffer if you are.
+//
+// The main uses for this class will be when performance is
+// critical and there's a convenient type to hold the cache's
+// entries. As described above, the number of bits required
+// for a cache entry is (kKeybits - kHashbits) + kValuebits. Suppose
+// kKeybits + kValuebits is 43. Then it probably makes sense to
+// chose kHashbits >= 11 so that cache entries fit in a uint32.
+//
+// On the other hand, suppose kKeybits = kValuebits = 64. Then
+// using this class may be less worthwhile. You'll probably
+// be using 128 bits for each entry anyway, so maybe just pick
+// a hash function, H, and use an array indexed by H(key):
+// void Put(K key, V value) { a_[H(key)] = pair<K, V>(key, value); }
+// V GetOrDefault(K key, V default) { const pair<K, V> &p = a_[H(key)]; ... }
+// etc.
+//
+// Further Details
+// ---------------
+//
+// For caches used only by one thread, the following is true:
+// 1. For a cache c,
+// (c.Put(key, value), c.GetOrDefault(key, 0)) == value
+// and
+// (c.Put(key, value), <...>, c.GetOrDefault(key, 0)) == value
+// if the elided code contains no c.Put calls.
+//
+// 2. Has(key) will return false if no <key, value> pair with that key
+// has ever been Put. However, a newly initialized cache will have
+// some <key, value> pairs already present. When you create a new
+// cache, you must specify an "initial value." The initialization
+// procedure is equivalent to Clear(initial_value), which is
+// equivalent to Put(k, initial_value) for all keys k from 0 to
+// 2^kHashbits - 1.
+//
+// 3. If key and key' differ then the only way Put(key, value) may
+// cause Has(key') to change is that Has(key') may change from true to
+// false. Furthermore, a Put() call that doesn't change Has(key')
+// doesn't change GetOrDefault(key', ...) either.
+//
+// Implementation details:
+//
+// This is a direct-mapped cache with 2^kHashbits entries;
+// the hash function simply takes the low bits of the key.
+// So, we don't have to store the low bits of the key in the entries.
+// Instead, an entry is the high bits of a key and a value, packed
+// together. E.g., a 20 bit key and a 7 bit value only require
+// a uint16 for each entry if kHashbits >= 11.
+//
+// Alternatives to this scheme will be added as needed.
+
+#ifndef TCMALLOC_PACKED_CACHE_INL_H__
+#define TCMALLOC_PACKED_CACHE_INL_H__
+
+#ifndef WTF_CHANGES
+#include "base/basictypes.h" // for COMPILE_ASSERT
+#include "base/logging.h" // for DCHECK
+#endif
+
+#ifndef DCHECK_EQ
+#define DCHECK_EQ(val1, val2) ASSERT((val1) == (val2))
+#endif
+
+// A safe way of doing "(1 << n) - 1" -- without worrying about overflow
+// Note this will all be resolved to a constant expression at compile-time
+#define N_ONES_(IntType, N) \
+ ( (N) == 0 ? 0 : ((static_cast<IntType>(1) << ((N)-1))-1 + \
+ (static_cast<IntType>(1) << ((N)-1))) )
+
+// The types K and V provide upper bounds on the number of valid keys
+// and values, but we explicitly require the keys to be less than
+// 2^kKeybits and the values to be less than 2^kValuebits. The size of
+// the table is controlled by kHashbits, and the type of each entry in
+// the cache is T. See also the big comment at the top of the file.
+template <int kKeybits, typename T>
+class PackedCache {
+ public:
+ typedef uintptr_t K;
+ typedef size_t V;
+ static const size_t kHashbits = 12;
+ static const size_t kValuebits = 8;
+
+ explicit PackedCache(V initial_value) {
+ COMPILE_ASSERT(kKeybits <= sizeof(K) * 8, key_size);
+ COMPILE_ASSERT(kValuebits <= sizeof(V) * 8, value_size);
+ COMPILE_ASSERT(kHashbits <= kKeybits, hash_function);
+ COMPILE_ASSERT(kKeybits - kHashbits + kValuebits <= kTbits,
+ entry_size_must_be_big_enough);
+ Clear(initial_value);
+ }
+
+ void Put(K key, V value) {
+ DCHECK_EQ(key, key & kKeyMask);
+ DCHECK_EQ(value, value & kValueMask);
+ array_[Hash(key)] = static_cast<T>(KeyToUpper(key) | value);
+ }
+
+ bool Has(K key) const {
+ DCHECK_EQ(key, key & kKeyMask);
+ return KeyMatch(array_[Hash(key)], key);
+ }
+
+ V GetOrDefault(K key, V default_value) const {
+ // As with other code in this class, we touch array_ as few times
+ // as we can. Assuming entries are read atomically (e.g., their
+ // type is uintptr_t on most hardware) then certain races are
+ // harmless.
+ DCHECK_EQ(key, key & kKeyMask);
+ T entry = array_[Hash(key)];
+ return KeyMatch(entry, key) ? EntryToValue(entry) : default_value;
+ }
+
+ void Clear(V value) {
+ DCHECK_EQ(value, value & kValueMask);
+ for (int i = 0; i < 1 << kHashbits; i++) {
+ array_[i] = static_cast<T>(value);
+ }
+ }
+
+ private:
+ // We are going to pack a value and the upper part of a key into
+ // an entry of type T. The UPPER type is for the upper part of a key,
+ // after the key has been masked and shifted for inclusion in an entry.
+ typedef T UPPER;
+
+ static V EntryToValue(T t) { return t & kValueMask; }
+
+ static UPPER EntryToUpper(T t) { return t & kUpperMask; }
+
+ // If v is a V and u is an UPPER then you can create an entry by
+ // doing u | v. kHashbits determines where in a K to find the upper
+ // part of the key, and kValuebits determines where in the entry to put
+ // it.
+ static UPPER KeyToUpper(K k) {
+ const int shift = kHashbits - kValuebits;
+ // Assume kHashbits >= kValuebits. It would be easy to lift this assumption.
+ return static_cast<T>(k >> shift) & kUpperMask;
+ }
+
+ // This is roughly the inverse of KeyToUpper(). Some of the key has been
+ // thrown away, since KeyToUpper() masks off the low bits of the key.
+ static K UpperToPartialKey(UPPER u) {
+ DCHECK_EQ(u, u & kUpperMask);
+ const int shift = kHashbits - kValuebits;
+ // Assume kHashbits >= kValuebits. It would be easy to lift this assumption.
+ return static_cast<K>(u) << shift;
+ }
+
+ static size_t Hash(K key) {
+ return static_cast<size_t>(key) & N_ONES_(size_t, kHashbits);
+ }
+
+ // Does the entry's partial key match the relevant part of the given key?
+ static bool KeyMatch(T entry, K key) {
+ return ((KeyToUpper(key) ^ entry) & kUpperMask) == 0;
+ }
+
+ static const size_t kTbits = 8 * sizeof(T);
+ static const int kUpperbits = kKeybits - kHashbits;
+
+ // For masking a K.
+ static const K kKeyMask = N_ONES_(K, kKeybits);
+
+ // For masking a T.
+ static const T kUpperMask = N_ONES_(T, kUpperbits) << kValuebits;
+
+ // For masking a V or a T.
+ static const V kValueMask = N_ONES_(V, kValuebits);
+
+ T array_[1 << kHashbits];
+};
+
+#undef N_ONES_
+
+#endif // TCMALLOC_PACKED_CACHE_INL_H__
diff --git a/Source/JavaScriptCore/wtf/TCPageMap.h b/Source/JavaScriptCore/wtf/TCPageMap.h
new file mode 100644
index 000000000..99bdc400e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TCPageMap.h
@@ -0,0 +1,316 @@
+// Copyright (c) 2005, 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.
+
+// ---
+// Author: Sanjay Ghemawat <opensource@google.com>
+//
+// A data structure used by the caching malloc. It maps from page# to
+// a pointer that contains info about that page. We use two
+// representations: one for 32-bit addresses, and another for 64 bit
+// addresses. Both representations provide the same interface. The
+// first representation is implemented as a flat array, the seconds as
+// a three-level radix tree that strips away approximately 1/3rd of
+// the bits every time.
+//
+// The BITS parameter should be the number of bits required to hold
+// a page number. E.g., with 32 bit pointers and 4K pages (i.e.,
+// page offset fits in lower 12 bits), BITS == 20.
+
+#ifndef TCMALLOC_PAGEMAP_H__
+#define TCMALLOC_PAGEMAP_H__
+
+#if HAVE(STDINT_H)
+#include <stdint.h>
+#elif HAVE(INTTYPES_H)
+#include <inttypes.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <string.h>
+#include "Assertions.h"
+
+// Single-level array
+template <int BITS>
+class TCMalloc_PageMap1 {
+ private:
+ void** array_;
+
+ public:
+ typedef uintptr_t Number;
+
+ void init(void* (*allocator)(size_t)) {
+ array_ = reinterpret_cast<void**>((*allocator)(sizeof(void*) << BITS));
+ memset(array_, 0, sizeof(void*) << BITS);
+ }
+
+ // 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, size_t) {
+ // Nothing to do since flat array was allocate at start
+ return true;
+ }
+
+ void PreallocateMoreMemory() {}
+
+ // REQUIRES "k" is in range "[0,2^BITS-1]".
+ // REQUIRES "k" has been ensured before.
+ //
+ // Return the current value for KEY. Returns "Value()" if not
+ // yet set.
+ void* get(Number k) const {
+ return array_[k];
+ }
+
+ // REQUIRES "k" is in range "[0,2^BITS-1]".
+ // REQUIRES "k" has been ensured before.
+ //
+ // Sets the value for KEY.
+ void set(Number k, void* v) {
+ array_[k] = v;
+ }
+};
+
+// Two-level radix tree
+template <int BITS>
+class TCMalloc_PageMap2 {
+ private:
+ // Put 32 entries in the root and (2^BITS)/32 entries in each leaf.
+ static const int ROOT_BITS = 5;
+ static const int ROOT_LENGTH = 1 << ROOT_BITS;
+
+ static const int LEAF_BITS = BITS - ROOT_BITS;
+ static const int LEAF_LENGTH = 1 << LEAF_BITS;
+
+ // Leaf node
+ struct Leaf {
+ void* values[LEAF_LENGTH];
+ };
+
+ Leaf* root_[ROOT_LENGTH]; // Pointers to 32 child nodes
+ void* (*allocator_)(size_t); // Memory allocator
+
+ public:
+ typedef uintptr_t Number;
+
+ void init(void* (*allocator)(size_t)) {
+ allocator_ = allocator;
+ memset(root_, 0, sizeof(root_));
+ }
+
+ void* get(Number k) const {
+ ASSERT(k >> BITS == 0);
+ const Number i1 = k >> LEAF_BITS;
+ const Number i2 = k & (LEAF_LENGTH-1);
+ return root_[i1]->values[i2];
+ }
+
+ void set(Number k, void* v) {
+ ASSERT(k >> BITS == 0);
+ const Number i1 = k >> LEAF_BITS;
+ const Number i2 = k & (LEAF_LENGTH-1);
+ root_[i1]->values[i2] = v;
+ }
+
+ bool Ensure(Number start, size_t n) {
+ for (Number key = start; key <= start + n - 1; ) {
+ const Number i1 = key >> LEAF_BITS;
+
+ // Make 2nd level node if necessary
+ if (root_[i1] == NULL) {
+ Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
+ if (leaf == NULL) return false;
+ memset(leaf, 0, sizeof(*leaf));
+ root_[i1] = leaf;
+ }
+
+ // Advance key past whatever is covered by this leaf node
+ key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
+ }
+ return true;
+ }
+
+ void PreallocateMoreMemory() {
+ // Allocate enough to keep track of all possible pages
+ Ensure(0, 1 << BITS);
+ }
+
+#ifdef WTF_CHANGES
+ template<class Visitor, class MemoryReader>
+ void visitValues(Visitor& visitor, const MemoryReader& reader)
+ {
+ for (int i = 0; i < ROOT_LENGTH; i++) {
+ if (!root_[i])
+ continue;
+
+ Leaf* l = reader(reinterpret_cast<Leaf*>(root_[i]));
+ for (int j = 0; j < LEAF_LENGTH; j += visitor.visit(l->values[j]))
+ ;
+ }
+ }
+
+ template<class Visitor, class MemoryReader>
+ void visitAllocations(Visitor& visitor, const MemoryReader&) {
+ for (int i = 0; i < ROOT_LENGTH; i++) {
+ if (root_[i])
+ visitor.visit(root_[i], sizeof(Leaf));
+ }
+ }
+#endif
+};
+
+// Three-level radix tree
+template <int BITS>
+class TCMalloc_PageMap3 {
+ private:
+ // How many bits should we consume at each interior level
+ static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up
+ static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;
+
+ // How many bits should we consume at leaf level
+ static const int LEAF_BITS = BITS - 2*INTERIOR_BITS;
+ static const int LEAF_LENGTH = 1 << LEAF_BITS;
+
+ // Interior node
+ struct Node {
+ Node* ptrs[INTERIOR_LENGTH];
+ };
+
+ // Leaf node
+ struct Leaf {
+ void* values[LEAF_LENGTH];
+ };
+
+ Node* root_; // Root of radix tree
+ void* (*allocator_)(size_t); // Memory allocator
+
+ Node* NewNode() {
+ Node* result = reinterpret_cast<Node*>((*allocator_)(sizeof(Node)));
+ if (result != NULL) {
+ memset(result, 0, sizeof(*result));
+ }
+ return result;
+ }
+
+ public:
+ typedef uintptr_t Number;
+
+ void init(void* (*allocator)(size_t)) {
+ allocator_ = allocator;
+ root_ = NewNode();
+ }
+
+ void* get(Number k) const {
+ ASSERT(k >> BITS == 0);
+ const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
+ const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
+ const Number i3 = k & (LEAF_LENGTH-1);
+ return reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3];
+ }
+
+ void set(Number k, void* v) {
+ ASSERT(k >> BITS == 0);
+ const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
+ const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
+ const Number i3 = k & (LEAF_LENGTH-1);
+ reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3] = v;
+ }
+
+ bool Ensure(Number start, size_t n) {
+ for (Number key = start; key <= start + n - 1; ) {
+ const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
+ const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1);
+
+ // Make 2nd level node if necessary
+ if (root_->ptrs[i1] == NULL) {
+ Node* n = NewNode();
+ if (n == NULL) return false;
+ root_->ptrs[i1] = n;
+ }
+
+ // Make leaf node if necessary
+ if (root_->ptrs[i1]->ptrs[i2] == NULL) {
+ Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
+ if (leaf == NULL) return false;
+ memset(leaf, 0, sizeof(*leaf));
+ root_->ptrs[i1]->ptrs[i2] = reinterpret_cast<Node*>(leaf);
+ }
+
+ // Advance key past whatever is covered by this leaf node
+ key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
+ }
+ return true;
+ }
+
+ void PreallocateMoreMemory() {
+ }
+
+#ifdef WTF_CHANGES
+ template<class Visitor, class MemoryReader>
+ void visitValues(Visitor& visitor, const MemoryReader& reader) {
+ Node* root = reader(root_);
+ for (int i = 0; i < INTERIOR_LENGTH; i++) {
+ if (!root->ptrs[i])
+ continue;
+
+ Node* n = reader(root->ptrs[i]);
+ for (int j = 0; j < INTERIOR_LENGTH; j++) {
+ if (!n->ptrs[j])
+ continue;
+
+ Leaf* l = reader(reinterpret_cast<Leaf*>(n->ptrs[j]));
+ for (int k = 0; k < LEAF_LENGTH; k += visitor.visit(l->values[k]))
+ ;
+ }
+ }
+ }
+
+ template<class Visitor, class MemoryReader>
+ void visitAllocations(Visitor& visitor, const MemoryReader& reader) {
+ visitor.visit(root_, sizeof(Node));
+
+ Node* root = reader(root_);
+ for (int i = 0; i < INTERIOR_LENGTH; i++) {
+ if (!root->ptrs[i])
+ continue;
+
+ visitor.visit(root->ptrs[i], sizeof(Node));
+ Node* n = reader(root->ptrs[i]);
+ for (int j = 0; j < INTERIOR_LENGTH; j++) {
+ if (!n->ptrs[j])
+ continue;
+
+ visitor.visit(n->ptrs[j], sizeof(Leaf));
+ }
+ }
+ }
+#endif
+};
+
+#endif // TCMALLOC_PAGEMAP_H__
diff --git a/Source/JavaScriptCore/wtf/TCSpinLock.h b/Source/JavaScriptCore/wtf/TCSpinLock.h
new file mode 100644
index 000000000..81b7d0cae
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TCSpinLock.h
@@ -0,0 +1,284 @@
+// 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
+// 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.
+
+// ---
+// Author: Sanjay Ghemawat <opensource@google.com>
+
+#ifndef TCMALLOC_INTERNAL_SPINLOCK_H__
+#define TCMALLOC_INTERNAL_SPINLOCK_H__
+
+#if (CPU(X86) || CPU(X86_64) || CPU(PPC)) && (COMPILER(GCC) || COMPILER(MSVC))
+
+#include <time.h> /* For nanosleep() */
+
+#if HAVE(STDINT_H)
+#include <stdint.h>
+#elif HAVE(INTTYPES_H)
+#include <inttypes.h>
+#else
+#include <sys/types.h>
+#endif
+
+#if OS(WINDOWS)
+#ifndef WIN32_LEAN_AND_MEAN
+#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);
+
+// The following is a struct so that it can be initialized at compile time
+struct TCMalloc_SpinLock {
+
+ inline void Lock() {
+ int r;
+#if COMPILER(GCC)
+#if CPU(X86) || CPU(X86_64)
+ __asm__ __volatile__
+ ("xchgl %0, %1"
+ : "=r"(r), "=m"(lockword_)
+ : "0"(1), "m"(lockword_)
+ : "memory");
+#else
+ volatile unsigned int *lockword_ptr = &lockword_;
+ __asm__ __volatile__
+ ("1: lwarx %0, 0, %1\n\t"
+ "stwcx. %2, 0, %1\n\t"
+ "bne- 1b\n\t"
+ "isync"
+ : "=&r" (r), "=r" (lockword_ptr)
+ : "r" (1), "1" (lockword_ptr)
+ : "memory");
+#endif
+#elif COMPILER(MSVC)
+ __asm {
+ mov eax, this ; store &lockword_ (which is this+0) in eax
+ mov ebx, 1 ; store 1 in ebx
+ xchg [eax], ebx ; exchange lockword_ and 1
+ mov r, ebx ; store old value of lockword_ in r
+ }
+#endif
+ if (r) TCMalloc_SlowLock(&lockword_);
+ }
+
+ inline void Unlock() {
+#if COMPILER(GCC)
+#if CPU(X86) || CPU(X86_64)
+ __asm__ __volatile__
+ ("movl $0, %0"
+ : "=m"(lockword_)
+ : "m" (lockword_)
+ : "memory");
+#else
+ __asm__ __volatile__
+ ("isync\n\t"
+ "eieio\n\t"
+ "stw %1, %0"
+#if OS(DARWIN) || CPU(PPC)
+ : "=o" (lockword_)
+#else
+ : "=m" (lockword_)
+#endif
+ : "r" (0)
+ : "memory");
+#endif
+#elif COMPILER(MSVC)
+ __asm {
+ mov eax, this ; store &lockword_ (which is this+0) in eax
+ mov [eax], 0 ; set lockword_ to 0
+ }
+#endif
+ }
+ // Report if we think the lock can be held by this thread.
+ // When the lock is truly held by the invoking thread
+ // we will always return true.
+ // Indended to be used as CHECK(lock.IsHeld());
+ inline bool IsHeld() const {
+ return lockword_ != 0;
+ }
+
+ inline void Init() { lockword_ = 0; }
+
+ volatile unsigned int lockword_;
+};
+
+#define SPINLOCK_INITIALIZER { 0 }
+
+static void TCMalloc_SlowLock(volatile unsigned int* lockword) {
+// Yield immediately since fast path failed
+#if OS(WINDOWS)
+ Sleep(0);
+#else
+ sched_yield();
+#endif
+ while (true) {
+ int r;
+#if COMPILER(GCC)
+#if CPU(X86) || CPU(X86_64)
+ __asm__ __volatile__
+ ("xchgl %0, %1"
+ : "=r"(r), "=m"(*lockword)
+ : "0"(1), "m"(*lockword)
+ : "memory");
+
+#else
+ int tmp = 1;
+ __asm__ __volatile__
+ ("1: lwarx %0, 0, %1\n\t"
+ "stwcx. %2, 0, %1\n\t"
+ "bne- 1b\n\t"
+ "isync"
+ : "=&r" (r), "=r" (lockword)
+ : "r" (tmp), "1" (lockword)
+ : "memory");
+#endif
+#elif COMPILER(MSVC)
+ __asm {
+ mov eax, lockword ; assign lockword into eax
+ mov ebx, 1 ; assign 1 into ebx
+ xchg [eax], ebx ; exchange *lockword and 1
+ mov r, ebx ; store old value of *lockword in r
+ }
+#endif
+ if (!r) {
+ return;
+ }
+
+ // This code was adapted from the ptmalloc2 implementation of
+ // spinlocks which would sched_yield() upto 50 times before
+ // sleeping once for a few milliseconds. Mike Burrows suggested
+ // just doing one sched_yield() outside the loop and always
+ // sleeping after that. This change helped a great deal on the
+ // performance of spinlocks under high contention. A test program
+ // with 10 threads on a dual Xeon (four virtual processors) went
+ // from taking 30 seconds to 16 seconds.
+
+ // Sleep for a few milliseconds
+#if OS(WINDOWS)
+ Sleep(2);
+#else
+ struct timespec tm;
+ tm.tv_sec = 0;
+ tm.tv_nsec = 2000001;
+ nanosleep(&tm, NULL);
+#endif
+ }
+}
+
+#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>
+
+// Portable version
+struct TCMalloc_SpinLock {
+ pthread_mutex_t private_lock_;
+
+ inline void Init() {
+ if (pthread_mutex_init(&private_lock_, NULL) != 0) CRASH();
+ }
+ inline void Finalize() {
+ if (pthread_mutex_destroy(&private_lock_) != 0) CRASH();
+ }
+ inline void Lock() {
+ if (pthread_mutex_lock(&private_lock_) != 0) CRASH();
+ }
+ inline void Unlock() {
+ if (pthread_mutex_unlock(&private_lock_) != 0) CRASH();
+ }
+ bool IsHeld() {
+ if (pthread_mutex_trylock(&private_lock_))
+ return true;
+
+ Unlock();
+ return false;
+ }
+};
+
+#define SPINLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+
+#endif
+
+// Corresponding locker object that arranges to acquire a spinlock for
+// the duration of a C++ scope.
+class TCMalloc_SpinLockHolder {
+ private:
+ TCMalloc_SpinLock* lock_;
+ public:
+ inline explicit TCMalloc_SpinLockHolder(TCMalloc_SpinLock* l)
+ : lock_(l) { l->Lock(); }
+ inline ~TCMalloc_SpinLockHolder() { lock_->Unlock(); }
+};
+
+// Short-hands for convenient use by tcmalloc.cc
+typedef TCMalloc_SpinLock SpinLock;
+typedef TCMalloc_SpinLockHolder SpinLockHolder;
+
+#endif // TCMALLOC_INTERNAL_SPINLOCK_H__
diff --git a/Source/JavaScriptCore/wtf/TCSystemAlloc.cpp b/Source/JavaScriptCore/wtf/TCSystemAlloc.cpp
new file mode 100644
index 000000000..1cd89e631
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TCSystemAlloc.cpp
@@ -0,0 +1,530 @@
+// Copyright (c) 2005, 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.
+
+// ---
+// Author: Sanjay Ghemawat
+
+#include "config.h"
+#if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+#include "TCSystemAlloc.h"
+
+#include <algorithm>
+#include "Assertions.h"
+#include "TCSpinLock.h"
+#include "UnusedParam.h"
+#include "VMTags.h"
+
+#if HAVE(STDINT_H)
+#include <stdint.h>
+#elif HAVE(INTTYPES_H)
+#include <inttypes.h>
+#else
+#include <sys/types.h>
+#endif
+
+#if OS(WINDOWS)
+#include "windows.h"
+#else
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+using namespace std;
+
+// Structure for discovering alignment
+union MemoryAligner {
+ void* p;
+ double d;
+ size_t s;
+};
+
+static SpinLock spinlock = SPINLOCK_INITIALIZER;
+
+// Page size is initialized on demand
+static size_t pagesize = 0;
+
+// Configuration parameters.
+//
+// if use_devmem is true, either use_sbrk or use_mmap must also be true.
+// For 2.2 kernels, it looks like the sbrk address space (500MBish) and
+// the mmap address space (1300MBish) are disjoint, so we need both allocators
+// to get as much virtual memory as possible.
+#ifndef WTF_CHANGES
+static bool use_devmem = false;
+#endif
+
+#if HAVE(SBRK)
+static bool use_sbrk = false;
+#endif
+
+#if HAVE(MMAP)
+static bool use_mmap = true;
+#endif
+
+#if HAVE(VIRTUALALLOC)
+static bool use_VirtualAlloc = true;
+#endif
+
+// Flags to keep us from retrying allocators that failed.
+static bool devmem_failure = false;
+static bool sbrk_failure = false;
+static bool mmap_failure = false;
+static bool VirtualAlloc_failure = false;
+
+#ifndef WTF_CHANGES
+DEFINE_int32(malloc_devmem_start, 0,
+ "Physical memory starting location in MB for /dev/mem allocation."
+ " Setting this to 0 disables /dev/mem allocation");
+DEFINE_int32(malloc_devmem_limit, 0,
+ "Physical memory limit location in MB for /dev/mem allocation."
+ " Setting this to 0 means no limit.");
+#else
+static const int32_t FLAGS_malloc_devmem_start = 0;
+static const int32_t FLAGS_malloc_devmem_limit = 0;
+#endif
+
+#if HAVE(SBRK)
+
+static void* TrySbrk(size_t size, size_t *actual_size, size_t alignment) {
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ // could theoretically return the "extra" bytes here, but this
+ // is simple and correct.
+ if (actual_size)
+ *actual_size = size;
+
+ void* result = sbrk(size);
+ if (result == reinterpret_cast<void*>(-1)) {
+ sbrk_failure = true;
+ return NULL;
+ }
+
+ // Is it aligned?
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
+ if ((ptr & (alignment-1)) == 0) return result;
+
+ // Try to get more memory for alignment
+ size_t extra = alignment - (ptr & (alignment-1));
+ void* r2 = sbrk(extra);
+ if (reinterpret_cast<uintptr_t>(r2) == (ptr + size)) {
+ // Contiguous with previous result
+ return reinterpret_cast<void*>(ptr + extra);
+ }
+
+ // Give up and ask for "size + alignment - 1" bytes so
+ // that we can find an aligned region within it.
+ result = sbrk(size + alignment - 1);
+ if (result == reinterpret_cast<void*>(-1)) {
+ sbrk_failure = true;
+ return NULL;
+ }
+ ptr = reinterpret_cast<uintptr_t>(result);
+ if ((ptr & (alignment-1)) != 0) {
+ ptr += alignment - (ptr & (alignment-1));
+ }
+ return reinterpret_cast<void*>(ptr);
+}
+
+#endif /* HAVE(SBRK) */
+
+#if HAVE(MMAP)
+
+static void* TryMmap(size_t size, size_t *actual_size, size_t alignment) {
+ // Enforce page alignment
+ if (pagesize == 0) pagesize = getpagesize();
+ if (alignment < pagesize) alignment = pagesize;
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ // could theoretically return the "extra" bytes here, but this
+ // is simple and correct.
+ if (actual_size)
+ *actual_size = size;
+
+ // Ask for extra memory if alignment > pagesize
+ size_t extra = 0;
+ if (alignment > pagesize) {
+ extra = alignment - pagesize;
+ }
+ void* result = mmap(NULL, size + extra,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ VM_TAG_FOR_TCMALLOC_MEMORY, 0);
+ if (result == reinterpret_cast<void*>(MAP_FAILED)) {
+ mmap_failure = true;
+ return NULL;
+ }
+
+ // Adjust the return memory so it is aligned
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
+ size_t adjust = 0;
+ if ((ptr & (alignment - 1)) != 0) {
+ adjust = alignment - (ptr & (alignment - 1));
+ }
+
+ // Return the unused memory to the system
+ if (adjust > 0) {
+ munmap(reinterpret_cast<void*>(ptr), adjust);
+ }
+ if (adjust < extra) {
+ munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
+ }
+
+ ptr += adjust;
+ return reinterpret_cast<void*>(ptr);
+}
+
+#endif /* HAVE(MMAP) */
+
+#if HAVE(VIRTUALALLOC)
+
+static void* TryVirtualAlloc(size_t size, size_t *actual_size, size_t alignment) {
+ // Enforce page alignment
+ if (pagesize == 0) {
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ pagesize = system_info.dwPageSize;
+ }
+
+ if (alignment < pagesize) alignment = pagesize;
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ // could theoretically return the "extra" bytes here, but this
+ // is simple and correct.
+ if (actual_size)
+ *actual_size = size;
+
+ // Ask for extra memory if alignment > pagesize
+ size_t extra = 0;
+ if (alignment > pagesize) {
+ extra = alignment - pagesize;
+ }
+ void* result = VirtualAlloc(NULL, size + extra,
+ MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
+ PAGE_READWRITE);
+
+ if (result == NULL) {
+ VirtualAlloc_failure = true;
+ return NULL;
+ }
+
+ // Adjust the return memory so it is aligned
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
+ size_t adjust = 0;
+ if ((ptr & (alignment - 1)) != 0) {
+ adjust = alignment - (ptr & (alignment - 1));
+ }
+
+ // Return the unused memory to the system - we'd like to release but the best we can do
+ // is decommit, since Windows only lets you free the whole allocation.
+ if (adjust > 0) {
+ VirtualFree(reinterpret_cast<void*>(ptr), adjust, MEM_DECOMMIT);
+ }
+ if (adjust < extra) {
+ VirtualFree(reinterpret_cast<void*>(ptr + adjust + size), extra-adjust, MEM_DECOMMIT);
+ }
+
+ ptr += adjust;
+ return reinterpret_cast<void*>(ptr);
+}
+
+#endif /* HAVE(MMAP) */
+
+#ifndef WTF_CHANGES
+static void* TryDevMem(size_t size, size_t *actual_size, size_t alignment) {
+ static bool initialized = false;
+ static off_t physmem_base; // next physical memory address to allocate
+ static off_t physmem_limit; // maximum physical address allowed
+ static int physmem_fd; // file descriptor for /dev/mem
+
+ // Check if we should use /dev/mem allocation. Note that it may take
+ // a while to get this flag initialized, so meanwhile we fall back to
+ // the next allocator. (It looks like 7MB gets allocated before
+ // this flag gets initialized -khr.)
+ if (FLAGS_malloc_devmem_start == 0) {
+ // NOTE: not a devmem_failure - we'd like TCMalloc_SystemAlloc to
+ // try us again next time.
+ return NULL;
+ }
+
+ if (!initialized) {
+ physmem_fd = open("/dev/mem", O_RDWR);
+ if (physmem_fd < 0) {
+ devmem_failure = true;
+ return NULL;
+ }
+ physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL;
+ physmem_limit = FLAGS_malloc_devmem_limit*1024LL*1024LL;
+ initialized = true;
+ }
+
+ // Enforce page alignment
+ if (pagesize == 0) pagesize = getpagesize();
+ if (alignment < pagesize) alignment = pagesize;
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ // could theoretically return the "extra" bytes here, but this
+ // is simple and correct.
+ if (actual_size)
+ *actual_size = size;
+
+ // Ask for extra memory if alignment > pagesize
+ size_t extra = 0;
+ if (alignment > pagesize) {
+ extra = alignment - pagesize;
+ }
+
+ // check to see if we have any memory left
+ if (physmem_limit != 0 && physmem_base + size + extra > physmem_limit) {
+ devmem_failure = true;
+ return NULL;
+ }
+ void *result = mmap(0, size + extra, PROT_READ | PROT_WRITE,
+ MAP_SHARED, physmem_fd, physmem_base);
+ if (result == reinterpret_cast<void*>(MAP_FAILED)) {
+ devmem_failure = true;
+ return NULL;
+ }
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
+
+ // Adjust the return memory so it is aligned
+ size_t adjust = 0;
+ if ((ptr & (alignment - 1)) != 0) {
+ adjust = alignment - (ptr & (alignment - 1));
+ }
+
+ // Return the unused virtual memory to the system
+ if (adjust > 0) {
+ munmap(reinterpret_cast<void*>(ptr), adjust);
+ }
+ if (adjust < extra) {
+ munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
+ }
+
+ ptr += adjust;
+ physmem_base += adjust + size;
+
+ return reinterpret_cast<void*>(ptr);
+}
+#endif
+
+void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) {
+ // Discard requests that overflow
+ if (size + alignment < size) return NULL;
+
+ SpinLockHolder lock_holder(&spinlock);
+
+ // Enforce minimum alignment
+ if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);
+
+ // Try twice, once avoiding allocators that failed before, and once
+ // more trying all allocators even if they failed before.
+ for (int i = 0; i < 2; i++) {
+
+#ifndef WTF_CHANGES
+ if (use_devmem && !devmem_failure) {
+ void* result = TryDevMem(size, actual_size, alignment);
+ if (result != NULL) return result;
+ }
+#endif
+
+#if HAVE(SBRK)
+ if (use_sbrk && !sbrk_failure) {
+ void* result = TrySbrk(size, actual_size, alignment);
+ if (result != NULL) return result;
+ }
+#endif
+
+#if HAVE(MMAP)
+ if (use_mmap && !mmap_failure) {
+ void* result = TryMmap(size, actual_size, alignment);
+ if (result != NULL) return result;
+ }
+#endif
+
+#if HAVE(VIRTUALALLOC)
+ if (use_VirtualAlloc && !VirtualAlloc_failure) {
+ void* result = TryVirtualAlloc(size, actual_size, alignment);
+ if (result != NULL) return result;
+ }
+#endif
+
+ // nothing worked - reset failure flags and try again
+ devmem_failure = false;
+ sbrk_failure = false;
+ mmap_failure = false;
+ VirtualAlloc_failure = false;
+ }
+ return NULL;
+}
+
+#if HAVE(MADV_FREE_REUSE)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+ int madviseResult;
+
+ while ((madviseResult = madvise(start, length, MADV_FREE_REUSABLE)) == -1 && errno == EAGAIN) { }
+
+ // Although really advisory, if madvise fail, we want to know about it.
+ ASSERT_UNUSED(madviseResult, madviseResult != -1);
+}
+
+#elif HAVE(MADV_FREE) || HAVE(MADV_DONTNEED)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+ // MADV_FREE clears the modified bit on pages, which allows
+ // them to be discarded immediately.
+#if HAVE(MADV_FREE)
+ const int advice = MADV_FREE;
+#else
+ const int advice = MADV_DONTNEED;
+#endif
+ if (FLAGS_malloc_devmem_start) {
+ // It's not safe to use MADV_DONTNEED if we've been mapping
+ // /dev/mem for heap memory
+ return;
+ }
+ if (pagesize == 0) pagesize = getpagesize();
+ const size_t pagemask = pagesize - 1;
+
+ size_t new_start = reinterpret_cast<size_t>(start);
+ size_t end = new_start + length;
+ size_t new_end = end;
+
+ // Round up the starting address and round down the ending address
+ // to be page aligned:
+ new_start = (new_start + pagesize - 1) & ~pagemask;
+ new_end = new_end & ~pagemask;
+
+ ASSERT((new_start & pagemask) == 0);
+ ASSERT((new_end & pagemask) == 0);
+ ASSERT(new_start >= reinterpret_cast<size_t>(start));
+ ASSERT(new_end <= end);
+
+ if (new_end > new_start) {
+ // Note -- ignoring most return codes, because if this fails it
+ // doesn't matter...
+ while (madvise(reinterpret_cast<char*>(new_start), new_end - new_start,
+ advice) == -1 &&
+ errno == EAGAIN) {
+ // NOP
+ }
+ }
+}
+
+#elif HAVE(MMAP)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+ void* newAddress = mmap(start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ // If the mmap failed then that's ok, we just won't return the memory to the system.
+ ASSERT_UNUSED(newAddress, newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED));
+}
+
+#elif HAVE(VIRTUALALLOC)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+ if (VirtualFree(start, length, MEM_DECOMMIT))
+ return;
+
+ // The decommit may fail if the memory region consists of allocations
+ // from more than one call to VirtualAlloc. In this case, fall back to
+ // using VirtualQuery to retrieve the allocation boundaries and decommit
+ // them each individually.
+
+ char* ptr = static_cast<char*>(start);
+ char* end = ptr + length;
+ MEMORY_BASIC_INFORMATION info;
+ while (ptr < end) {
+ size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
+ ASSERT_UNUSED(resultSize, resultSize == sizeof(info));
+
+ size_t decommitSize = min<size_t>(info.RegionSize, end - ptr);
+ BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
+ ASSERT_UNUSED(success, success);
+ ptr += decommitSize;
+ }
+}
+
+#else
+
+// Platforms that don't support returning memory use an empty inline version of TCMalloc_SystemRelease
+// declared in TCSystemAlloc.h
+
+#endif
+
+#if HAVE(MADV_FREE_REUSE)
+
+void TCMalloc_SystemCommit(void* start, size_t length)
+{
+ while (madvise(start, length, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
+}
+
+#elif HAVE(VIRTUALALLOC)
+
+void TCMalloc_SystemCommit(void* start, size_t length)
+{
+ if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
+ return;
+
+ // The commit may fail if the memory region consists of allocations
+ // from more than one call to VirtualAlloc. In this case, fall back to
+ // using VirtualQuery to retrieve the allocation boundaries and commit them
+ // each individually.
+
+ char* ptr = static_cast<char*>(start);
+ char* end = ptr + length;
+ MEMORY_BASIC_INFORMATION info;
+ while (ptr < end) {
+ size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
+ ASSERT_UNUSED(resultSize, resultSize == sizeof(info));
+
+ size_t commitSize = min<size_t>(info.RegionSize, end - ptr);
+ void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT, PAGE_READWRITE);
+ ASSERT_UNUSED(newAddress, newAddress == ptr);
+ ptr += commitSize;
+ }
+}
+
+#else
+
+// Platforms that don't need to explicitly commit memory use an empty inline version of TCMalloc_SystemCommit
+// declared in TCSystemAlloc.h
+
+#endif
+
+#endif // #if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+
diff --git a/Source/JavaScriptCore/wtf/TCSystemAlloc.h b/Source/JavaScriptCore/wtf/TCSystemAlloc.h
new file mode 100644
index 000000000..1c677889c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TCSystemAlloc.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2005, 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.
+
+// ---
+// Author: Sanjay Ghemawat
+//
+// Routine that uses sbrk/mmap to allocate memory from the system.
+// Useful for implementing malloc.
+
+#ifndef TCMALLOC_SYSTEM_ALLOC_H__
+#define TCMALLOC_SYSTEM_ALLOC_H__
+
+// REQUIRES: "alignment" is a power of two or "0" to indicate default alignment
+//
+// Allocate and return "N" bytes of zeroed memory.
+//
+// If actual_bytes is NULL then the returned memory is exactly the
+// requested size. If actual bytes is non-NULL then the allocator
+// may optionally return more bytes than asked for (i.e. return an
+// entire "huge" page if a huge page allocator is in use).
+//
+// The returned pointer is a multiple of "alignment" if non-zero.
+//
+// Returns NULL when out of memory.
+extern void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes,
+ size_t alignment = 0);
+
+// This call is a hint to the operating system that the pages
+// contained in the specified range of memory will not be used for a
+// while, and can be released for use by other processes or the OS.
+// Pages which are released in this way may be destroyed (zeroed) by
+// the OS. The benefit of this function is that it frees memory for
+// use by the system, the cost is that the pages are faulted back into
+// the address space next time they are touched, which can impact
+// performance. (Only pages fully covered by the memory region will
+// be released, partial pages will not.)
+extern void TCMalloc_SystemRelease(void* start, size_t length);
+
+extern void TCMalloc_SystemCommit(void* start, size_t length);
+
+#if !HAVE(MADV_FREE_REUSE) && !HAVE(MADV_DONTNEED) && !HAVE(MMAP) && !HAVE(VIRTUALALLOC)
+inline void TCMalloc_SystemRelease(void*, size_t) { }
+#endif
+
+#if !HAVE(VIRTUALALLOC) && !HAVE(MADV_FREE_REUSE)
+inline void TCMalloc_SystemCommit(void*, size_t) { }
+#endif
+
+#endif /* TCMALLOC_SYSTEM_ALLOC_H__ */
diff --git a/Source/JavaScriptCore/wtf/TemporaryChange.h b/Source/JavaScriptCore/wtf/TemporaryChange.h
new file mode 100644
index 000000000..fe374b194
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TemporaryChange.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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 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 TemporaryChange_h
+#define TemporaryChange_h
+
+#include "Noncopyable.h"
+
+namespace WTF {
+
+// TemporaryChange<> is useful for setting a variable to a new value only within a
+// particular scope. An TemporaryChange<> object changes a variable to its original
+// value upon destruction, making it an alternative to writing "var = false;"
+// or "var = oldVal;" at all of a block's exit points.
+//
+// This should be obvious, but note that an TemporaryChange<> instance should have a
+// shorter lifetime than its scopedVariable, to prevent invalid memory writes
+// when the TemporaryChange<> object is destroyed.
+
+template<typename T>
+class TemporaryChange {
+ WTF_MAKE_NONCOPYABLE(TemporaryChange);
+public:
+ TemporaryChange(T& scopedVariable, T newValue)
+ : m_scopedVariable(scopedVariable)
+ , m_originalValue(scopedVariable)
+ {
+ m_scopedVariable = newValue;
+ }
+
+ ~TemporaryChange()
+ {
+ m_scopedVariable = m_originalValue;
+ }
+
+
+private:
+ T& m_scopedVariable;
+ T m_originalValue;
+};
+
+}
+
+using WTF::TemporaryChange;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/ThreadFunctionInvocation.h b/Source/JavaScriptCore/wtf/ThreadFunctionInvocation.h
new file mode 100644
index 000000000..f1e147268
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadFunctionInvocation.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007, 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 ThreadFunctionInvocation_h
+#define ThreadFunctionInvocation_h
+
+namespace WTF {
+
+typedef void* (*ThreadFunction)(void* argument);
+
+struct ThreadFunctionInvocation {
+ ThreadFunctionInvocation(ThreadFunction function, void* data)
+ : function(function)
+ , data(data)
+ {
+ }
+
+ ThreadFunction function;
+ void* data;
+};
+
+} // namespace WTF
+
+#endif // ThreadFunctionInvocation_h
diff --git a/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp b/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp
new file mode 100644
index 000000000..b3b690f70
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009, 2011 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"
+
+#if USE(PTHREADS)
+
+#include "ThreadIdentifierDataPthreads.h"
+
+#include "Threading.h"
+
+#if OS(ANDROID)
+// PTHREAD_KEYS_MAX is not defined in bionic, so explicitly define it here.
+#define PTHREAD_KEYS_MAX 1024
+#else
+#include <limits.h>
+#endif
+
+namespace WTF {
+
+pthread_key_t ThreadIdentifierData::m_key = PTHREAD_KEYS_MAX;
+
+void clearPthreadHandleForIdentifier(ThreadIdentifier);
+
+ThreadIdentifierData::~ThreadIdentifierData()
+{
+ clearPthreadHandleForIdentifier(m_identifier);
+}
+
+void ThreadIdentifierData::initializeOnce()
+{
+ if (pthread_key_create(&m_key, destruct))
+ CRASH();
+}
+
+ThreadIdentifier ThreadIdentifierData::identifier()
+{
+ ASSERT(m_key != PTHREAD_KEYS_MAX);
+ ThreadIdentifierData* threadIdentifierData = static_cast<ThreadIdentifierData*>(pthread_getspecific(m_key));
+
+ return threadIdentifierData ? threadIdentifierData->m_identifier : 0;
+}
+
+void ThreadIdentifierData::initialize(ThreadIdentifier id)
+{
+ ASSERT(!identifier());
+ pthread_setspecific(m_key, new ThreadIdentifierData(id));
+}
+
+void ThreadIdentifierData::destruct(void* data)
+{
+ ThreadIdentifierData* threadIdentifierData = static_cast<ThreadIdentifierData*>(data);
+ ASSERT(threadIdentifierData);
+
+ if (threadIdentifierData->m_isDestroyedOnce) {
+ delete threadIdentifierData;
+ return;
+ }
+
+ threadIdentifierData->m_isDestroyedOnce = true;
+ // Re-setting the value for key causes another destruct() call after all other thread-specific destructors were called.
+ pthread_setspecific(m_key, threadIdentifierData);
+}
+
+} // namespace WTF
+
+#endif // USE(PTHREADS)
diff --git a/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h b/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h
new file mode 100644
index 000000000..84349a0cd
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h
@@ -0,0 +1,78 @@
+/*
+ * 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 ThreadIdentifierDataPthreads_h
+#define ThreadIdentifierDataPthreads_h
+
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+// Holds ThreadIdentifier in the thread-specific storage and employs pthreads-specific 2-pass destruction to reliably remove
+// ThreadIdentifier from threadMap. It assumes regular ThreadSpecific types don't use multiple-pass destruction.
+class ThreadIdentifierData {
+ WTF_MAKE_NONCOPYABLE(ThreadIdentifierData);
+public:
+ ~ThreadIdentifierData();
+
+ // One time initialization for this class as a whole.
+ // This method must be called before initialize() and it is not thread-safe.
+ static void initializeOnce();
+
+ // Creates and puts an instance of ThreadIdentifierData into thread-specific storage.
+ static void initialize(ThreadIdentifier identifier);
+
+ // Returns 0 if thread-specific storage was not initialized.
+ static ThreadIdentifier identifier();
+
+private:
+ ThreadIdentifierData(ThreadIdentifier identifier)
+ : m_identifier(identifier)
+ , m_isDestroyedOnce(false)
+ {
+ }
+
+ // This thread-specific destructor is called 2 times when thread terminates:
+ // - first, when all the other thread-specific destructors are called, it simply remembers it was 'destroyed once'
+ // and re-sets itself into the thread-specific slot to make Pthreads to call it again later.
+ // - second, after all thread-specific destructors were invoked, it gets called again - this time, we remove the
+ // ThreadIdentifier from the threadMap, completing the cleanup.
+ static void destruct(void* data);
+
+ ThreadIdentifier m_identifier;
+ bool m_isDestroyedOnce;
+ static pthread_key_t m_key;
+};
+
+} // namespace WTF
+
+#endif // ThreadIdentifierDataPthreads_h
+
+
diff --git a/Source/JavaScriptCore/wtf/ThreadRestrictionVerifier.h b/Source/JavaScriptCore/wtf/ThreadRestrictionVerifier.h
new file mode 100644
index 000000000..0eeac8e62
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadRestrictionVerifier.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 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 ThreadRestrictionVerifier_h
+#define ThreadRestrictionVerifier_h
+
+#include <wtf/Assertions.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+
+#if HAVE(DISPATCH_H)
+#include <dispatch/dispatch.h>
+#endif
+
+#ifndef NDEBUG
+
+namespace WTF {
+
+// Verifies that a class is used in a way that respects its lack of thread-safety.
+// The default mode is to verify that the object will only be used on a single thread. The
+// thread gets captured when setShared(true) is called.
+// The mode may be changed by calling useMutexMode (or turnOffVerification).
+class ThreadRestrictionVerifier {
+public:
+ ThreadRestrictionVerifier()
+ : m_mode(SingleThreadVerificationMode)
+ , m_shared(false)
+ , m_owningThread(0)
+ , m_mutex(0)
+#if HAVE(DISPATCH_H)
+ , m_owningQueue(0)
+#endif
+ {
+ }
+
+#if HAVE(DISPATCH_H)
+ ~ThreadRestrictionVerifier()
+ {
+ if (m_owningQueue)
+ dispatch_release(m_owningQueue);
+ }
+#endif
+
+ void setMutexMode(Mutex& mutex)
+ {
+ ASSERT(m_mode == SingleThreadVerificationMode || (m_mode == MutexVerificationMode && &mutex == m_mutex));
+ m_mode = MutexVerificationMode;
+ m_mutex = &mutex;
+ }
+
+#if HAVE(DISPATCH_H)
+ void setDispatchQueueMode(dispatch_queue_t queue)
+ {
+ ASSERT(m_mode == SingleThreadVerificationMode);
+ m_mode = SingleDispatchQueueVerificationMode;
+ m_owningQueue = queue;
+ dispatch_retain(m_owningQueue);
+ }
+#endif
+
+ void turnOffVerification()
+ {
+ ASSERT(m_mode == SingleThreadVerificationMode);
+ m_mode = NoVerificationMode;
+ }
+
+ // Indicates that the object may (or may not) be owned by more than one place.
+ void setShared(bool shared)
+ {
+#if !ASSERT_DISABLED
+ bool previouslyShared = m_shared;
+#endif
+ m_shared = shared;
+
+ if (!m_shared)
+ return;
+
+ switch (m_mode) {
+ case SingleThreadVerificationMode:
+ ASSERT(shared != previouslyShared);
+ // Capture the current thread to verify that subsequent ref/deref happen on this thread.
+ m_owningThread = currentThread();
+ return;
+
+#if HAVE(DISPATCH_H)
+ case SingleDispatchQueueVerificationMode:
+#endif
+ case MutexVerificationMode:
+ case NoVerificationMode:
+ return;
+ }
+ ASSERT_NOT_REACHED();
+ }
+
+ // Is it OK to use the object at this moment on the current thread?
+ bool isSafeToUse() const
+ {
+ if (!m_shared)
+ return true;
+
+ switch (m_mode) {
+ case SingleThreadVerificationMode:
+ return m_owningThread == currentThread();
+
+ case MutexVerificationMode:
+ if (!m_mutex->tryLock())
+ return true;
+ m_mutex->unlock();
+ return false;
+
+#if HAVE(DISPATCH_H)
+ case SingleDispatchQueueVerificationMode:
+ return m_owningQueue == dispatch_get_current_queue();
+#endif
+
+ case NoVerificationMode:
+ return true;
+ }
+ ASSERT_NOT_REACHED();
+ return true;
+ }
+
+private:
+ enum VerificationMode {
+ SingleThreadVerificationMode,
+ MutexVerificationMode,
+ NoVerificationMode,
+#if HAVE(DISPATCH_H)
+ SingleDispatchQueueVerificationMode,
+#endif
+ };
+
+ VerificationMode m_mode;
+ bool m_shared;
+
+ // Used by SingleThreadVerificationMode
+ ThreadIdentifier m_owningThread;
+
+ // Used by MutexVerificationMode.
+ Mutex* m_mutex;
+
+#if HAVE(DISPATCH_H)
+ // Used by SingleDispatchQueueVerificationMode.
+ dispatch_queue_t m_owningQueue;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/JavaScriptCore/wtf/ThreadSafeRefCounted.h b/Source/JavaScriptCore/wtf/ThreadSafeRefCounted.h
new file mode 100644
index 000000000..8497b3bc2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadSafeRefCounted.h
@@ -0,0 +1,150 @@
+/*
+ * 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 ThreadSafeRefCounted_h
+#define ThreadSafeRefCounted_h
+
+#include "Platform.h"
+
+#include <wtf/Atomics.h>
+#include <wtf/DynamicAnnotations.h>
+#include <wtf/ThreadingPrimitives.h>
+
+namespace WTF {
+
+class ThreadSafeRefCountedBase {
+ WTF_MAKE_NONCOPYABLE(ThreadSafeRefCountedBase);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ThreadSafeRefCountedBase(int initialRefCount = 1)
+ : m_refCount(initialRefCount)
+ {
+ }
+
+ void ref()
+ {
+#if USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ atomicIncrement(&m_refCount);
+#else
+ MutexLocker locker(m_mutex);
+ ++m_refCount;
+#endif
+ }
+
+ bool hasOneRef()
+ {
+ return refCount() == 1;
+ }
+
+ int refCount() const
+ {
+#if !USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ 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_THREADSAFEREFCOUNTED)
+ WTF_ANNOTATE_HAPPENS_BEFORE(&m_refCount);
+ if (atomicDecrement(&m_refCount) <= 0) {
+ WTF_ANNOTATE_HAPPENS_AFTER(&m_refCount);
+ return true;
+ }
+#else
+ int refCount;
+ {
+ MutexLocker locker(m_mutex);
+ --m_refCount;
+ refCount = m_refCount;
+ }
+ if (refCount <= 0)
+ return true;
+#endif
+ return false;
+ }
+
+private:
+ int m_refCount;
+#if !USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ mutable Mutex m_mutex;
+#endif
+};
+
+template<class T> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
+public:
+ void deref()
+ {
+ if (derefBase())
+ delete static_cast<T*>(this);
+ }
+
+protected:
+ ThreadSafeRefCounted()
+ {
+ }
+};
+
+} // namespace WTF
+
+using WTF::ThreadSafeRefCounted;
+
+#endif // ThreadSafeRefCounted_h
diff --git a/Source/JavaScriptCore/wtf/ThreadSpecific.h b/Source/JavaScriptCore/wtf/ThreadSpecific.h
new file mode 100644
index 000000000..7c75a83ee
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadSpecific.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Jian Li <jianli@chromium.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.
+ * 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.
+ */
+
+/* Thread local storage is implemented by using either pthread API or Windows
+ * native API. There is subtle semantic discrepancy for the cleanup function
+ * implementation as noted below:
+ * @ In pthread implementation, the destructor function will be called
+ * repeatedly if there is still non-NULL value associated with the function.
+ * @ In Windows native implementation, the destructor function will be called
+ * only once.
+ * This semantic discrepancy does not impose any problem because nowhere in
+ * WebKit the repeated call bahavior is utilized.
+ */
+
+#ifndef WTF_ThreadSpecific_h
+#define WTF_ThreadSpecific_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
+
+#if USE(PTHREADS)
+#include <pthread.h>
+#elif PLATFORM(GTK)
+#include <glib.h>
+#elif OS(WINDOWS)
+#include <windows.h>
+#endif
+
+namespace WTF {
+
+#if 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();
+#endif
+
+template<typename T> class ThreadSpecific {
+ WTF_MAKE_NONCOPYABLE(ThreadSpecific);
+public:
+ ThreadSpecific();
+ bool isSet(); // Useful as a fast check to see if this thread has set this value.
+ T* operator->();
+ operator T*();
+ T& operator*();
+
+private:
+#if 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) || PLATFORM(GTK) || OS(WINDOWS)
+ struct Data {
+ WTF_MAKE_NONCOPYABLE(Data);
+ public:
+ Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
+
+ T* value;
+ ThreadSpecific<T>* owner;
+#if OS(WINDOWS)
+ void (*destructor)(void*);
+#endif
+ };
+#endif
+
+#if USE(PTHREADS)
+ pthread_key_t m_key;
+#elif PLATFORM(GTK)
+ GStaticPrivate m_key;
+#elif OS(WINDOWS)
+ int m_index;
+#endif
+};
+
+#if USE(PTHREADS)
+template<typename T>
+inline ThreadSpecific<T>::ThreadSpecific()
+{
+ int error = pthread_key_create(&m_key, destroy);
+ if (error)
+ CRASH();
+}
+
+template<typename T>
+inline T* ThreadSpecific<T>::get()
+{
+ Data* data = static_cast<Data*>(pthread_getspecific(m_key));
+ return data ? data->value : 0;
+}
+
+template<typename T>
+inline void ThreadSpecific<T>::set(T* ptr)
+{
+ ASSERT(!get());
+ pthread_setspecific(m_key, new Data(ptr, this));
+}
+
+#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*>(g_static_private_get(&m_key));
+ return data ? data->value : 0;
+}
+
+template<typename T>
+inline void ThreadSpecific<T>::set(T* ptr)
+{
+ ASSERT(!get());
+ Data* data = new Data(ptr, this);
+ g_static_private_set(&m_key, data, destroy);
+}
+
+#elif OS(WINDOWS)
+
+// TLS_OUT_OF_INDEXES is not defined on WinCE.
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
+
+// The maximum number of TLS keys that can be created. For simplification, we assume that:
+// 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies.
+// 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough.
+const int kMaxTlsKeySize = 256;
+
+long& tlsKeyCount();
+DWORD* tlsKeys();
+
+template<typename T>
+inline ThreadSpecific<T>::ThreadSpecific()
+ : m_index(-1)
+{
+ DWORD tlsKey = TlsAlloc();
+ if (tlsKey == TLS_OUT_OF_INDEXES)
+ CRASH();
+
+ m_index = InterlockedIncrement(&tlsKeyCount()) - 1;
+ if (m_index >= kMaxTlsKeySize)
+ CRASH();
+ tlsKeys()[m_index] = tlsKey;
+}
+
+template<typename T>
+inline ThreadSpecific<T>::~ThreadSpecific()
+{
+ // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached.
+ TlsFree(tlsKeys()[m_index]);
+}
+
+template<typename T>
+inline T* ThreadSpecific<T>::get()
+{
+ Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index]));
+ return data ? data->value : 0;
+}
+
+template<typename T>
+inline void ThreadSpecific<T>::set(T* ptr)
+{
+ ASSERT(!get());
+ Data* data = new Data(ptr, this);
+ data->destructor = &ThreadSpecific<T>::destroy;
+ TlsSetValue(tlsKeys()[m_index], data);
+}
+
+#else
+#error ThreadSpecific is not implemented for this platform.
+#endif
+
+template<typename T>
+inline void ThreadSpecific<T>::destroy(void* ptr)
+{
+ Data* data = static_cast<Data*>(ptr);
+
+#if USE(PTHREADS)
+ // 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
+
+ data->value->~T();
+ fastFree(data->value);
+
+#if USE(PTHREADS)
+ pthread_setspecific(data->owner->m_key, 0);
+#elif PLATFORM(GTK)
+ g_static_private_set(&data->owner->m_key, 0, 0);
+#elif OS(WINDOWS)
+ TlsSetValue(tlsKeys()[data->owner->m_index], 0);
+#else
+#error ThreadSpecific is not implemented for this platform.
+#endif
+
+ delete data;
+}
+
+template<typename T>
+inline bool ThreadSpecific<T>::isSet()
+{
+ return !!get();
+}
+
+template<typename T>
+inline ThreadSpecific<T>::operator T*()
+{
+ T* ptr = static_cast<T*>(get());
+ 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*>(fastZeroedMalloc(sizeof(T)));
+ set(ptr);
+ new (NotNull, ptr) T;
+ }
+ return ptr;
+}
+
+template<typename T>
+inline T* ThreadSpecific<T>::operator->()
+{
+ return operator T*();
+}
+
+template<typename T>
+inline T& ThreadSpecific<T>::operator*()
+{
+ return *operator T*();
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/ThreadSpecificWin.cpp b/Source/JavaScriptCore/wtf/ThreadSpecificWin.cpp
new file mode 100644
index 000000000..d72996a7a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadSpecificWin.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009 Jian Li <jianli@chromium.org>
+ *
+ * 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 "ThreadSpecific.h"
+
+#if USE(PTHREADS)
+#error This file should not be compiled by ports that do not use Windows native ThreadSpecific implementation.
+#endif
+
+namespace WTF {
+
+long& tlsKeyCount()
+{
+ static long count;
+ return count;
+}
+
+DWORD* tlsKeys()
+{
+ static DWORD keys[kMaxTlsKeySize];
+ return keys;
+}
+
+void ThreadSpecificThreadExit()
+{
+ for (long i = 0; i < tlsKeyCount(); i++) {
+ // The layout of ThreadSpecific<T>::Data does not depend on T. So we are safe to do the static cast to ThreadSpecific<int> in order to access its data member.
+ ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
+ if (data)
+ data->destructor(data);
+ }
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/Threading.cpp b/Source/JavaScriptCore/wtf/Threading.cpp
new file mode 100644
index 000000000..f2e0565e9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Threading.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 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 "Threading.h"
+
+#include <string.h>
+
+namespace WTF {
+
+struct NewThreadContext {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ NewThreadContext(ThreadFunction entryPoint, void* data, const char* name)
+ : entryPoint(entryPoint)
+ , data(data)
+ , name(name)
+ {
+ }
+
+ ThreadFunction entryPoint;
+ void* data;
+ const char* name;
+
+ Mutex creationMutex;
+};
+
+static void* threadEntryPoint(void* contextData)
+{
+ NewThreadContext* context = reinterpret_cast<NewThreadContext*>(contextData);
+
+ // Block until our creating thread has completed any extra setup work, including
+ // establishing ThreadIdentifier.
+ {
+ MutexLocker locker(context->creationMutex);
+ }
+
+ initializeCurrentThreadInternal(context->name);
+
+ // Grab the info that we need out of the context, then deallocate it.
+ ThreadFunction entryPoint = context->entryPoint;
+ void* data = context->data;
+ delete context;
+
+ return entryPoint(data);
+}
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name)
+{
+ // Visual Studio has a 31-character limit on thread names. Longer names will
+ // be truncated silently, but we'd like callers to know about the limit.
+#if !LOG_DISABLED
+ if (strlen(name) > 31)
+ LOG_ERROR("Thread name \"%s\" is longer than 31 characters and will be truncated by Visual Studio", name);
+#endif
+
+ NewThreadContext* context = new NewThreadContext(entryPoint, data, name);
+
+ // Prevent the thread body from executing until we've established the thread identifier.
+ MutexLocker locker(context->creationMutex);
+
+ return createThreadInternal(threadEntryPoint, context, name);
+}
+
+#if PLATFORM(MAC) || PLATFORM(WIN)
+
+// This function is deprecated but needs to be kept around for backward
+// compatibility. Use the 3-argument version of createThread above.
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data);
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
+{
+ return createThread(entryPoint, data, 0);
+}
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/Threading.h b/Source/JavaScriptCore/wtf/Threading.h
new file mode 100644
index 000000000..3a89757a9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Threading.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 Threading_h
+#define Threading_h
+
+#include "Platform.h"
+
+#include <stdint.h>
+#include <wtf/Assertions.h>
+#include <wtf/Atomics.h>
+#include <wtf/Locker.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadSafeRefCounted.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) \
+ WTF::lockAtomicallyInitializedStaticMutex(); \
+ static T name; \
+ WTF::unlockAtomicallyInitializedStaticMutex();
+
+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);
+
+// Internal platform-specific createThread implementation.
+ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName);
+
+// Called in the thread during initialization.
+// Helpful for platforms where the thread name must be set from within the thread.
+void initializeCurrentThreadInternal(const char* threadName);
+
+ThreadIdentifier currentThread();
+int waitForThreadCompletion(ThreadIdentifier, void**);
+void detachThread(ThreadIdentifier);
+
+void yield();
+
+void lockAtomicallyInitializedStaticMutex();
+void unlockAtomicallyInitializedStaticMutex();
+
+} // namespace WTF
+
+using WTF::ThreadIdentifier;
+using WTF::createThread;
+using WTF::currentThread;
+using WTF::detachThread;
+using WTF::waitForThreadCompletion;
+using WTF::yield;
+
+#endif // Threading_h
diff --git a/Source/JavaScriptCore/wtf/ThreadingNone.cpp b/Source/JavaScriptCore/wtf/ThreadingNone.cpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadingNone.cpp
diff --git a/Source/JavaScriptCore/wtf/ThreadingPrimitives.h b/Source/JavaScriptCore/wtf/ThreadingPrimitives.h
new file mode 100644
index 000000000..1bed5d3ae
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadingPrimitives.h
@@ -0,0 +1,151 @@
+/*
+ * 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/FastAllocBase.h>
+#include <wtf/Locker.h>
+#include <wtf/Noncopyable.h>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
+#if USE(PTHREADS)
+#include <pthread.h>
+#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 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 {
+ WTF_MAKE_NONCOPYABLE(Mutex); WTF_MAKE_FAST_ALLOCATED;
+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 {
+ WTF_MAKE_NONCOPYABLE(ReadWriteLock);
+public:
+ ReadWriteLock();
+ ~ReadWriteLock();
+
+ void readLock();
+ bool tryReadLock();
+
+ void writeLock();
+ bool tryWriteLock();
+
+ void unlock();
+
+private:
+ PlatformReadWriteLock m_readWriteLock;
+};
+
+class ThreadCondition {
+ WTF_MAKE_NONCOPYABLE(ThreadCondition);
+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)
+// The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime().
+// Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject).
+DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime);
+#endif
+
+} // namespace WTF
+
+using WTF::Mutex;
+using WTF::MutexLocker;
+using WTF::ThreadCondition;
+
+#if OS(WINDOWS)
+using WTF::absoluteTimeToWaitTimeoutInterval;
+#endif
+
+#endif // ThreadingPrimitives_h
diff --git a/Source/JavaScriptCore/wtf/ThreadingPthreads.cpp b/Source/JavaScriptCore/wtf/ThreadingPthreads.cpp
new file mode 100644
index 000000000..763ec2bbb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadingPthreads.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ * Copyright (C) 2011 Research In Motion Limited. 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.
+ */
+
+#include "config.h"
+#include "Threading.h"
+
+#if USE(PTHREADS)
+
+#include "CurrentTime.h"
+#include "DateMath.h"
+#include "dtoa.h"
+#include "dtoa/cached-powers.h"
+#include "HashMap.h"
+#include "RandomNumberSeed.h"
+#include "StdLibExtras.h"
+#include "ThreadIdentifierDataPthreads.h"
+#include "ThreadSpecific.h"
+#include "UnusedParam.h"
+#include <wtf/WTFThreadData.h>
+#include <errno.h>
+
+#if !COMPILER(MSVC)
+#include <limits.h>
+#include <sched.h>
+#include <sys/time.h>
+#endif
+
+#if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
+#include <objc/objc-auto.h>
+#endif
+
+#if PLATFORM(BLACKBERRY)
+#include <BlackBerryPlatformMisc.h>
+#include <BlackBerryPlatformSettings.h>
+#endif
+
+namespace WTF {
+
+typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
+
+static Mutex* atomicallyInitializedStaticMutex;
+
+void clearPthreadHandleForIdentifier(ThreadIdentifier);
+
+static Mutex& threadMapMutex()
+{
+ DEFINE_STATIC_LOCAL(Mutex, mutex, ());
+ return mutex;
+}
+
+void initializeThreading()
+{
+ if (atomicallyInitializedStaticMutex)
+ return;
+
+ WTF::double_conversion::initialize();
+ // StringImpl::empty() does not construct its static string in a threadsafe fashion,
+ // so ensure it has been initialized from here.
+ StringImpl::empty();
+ atomicallyInitializedStaticMutex = new Mutex;
+ threadMapMutex();
+ initializeRandomNumberGenerator();
+ ThreadIdentifierData::initializeOnce();
+ wtfThreadData();
+ s_dtoaP5Mutex = new Mutex;
+ initializeDates();
+}
+
+void lockAtomicallyInitializedStaticMutex()
+{
+ ASSERT(atomicallyInitializedStaticMutex);
+ atomicallyInitializedStaticMutex->lock();
+}
+
+void unlockAtomicallyInitializedStaticMutex()
+{
+ atomicallyInitializedStaticMutex->unlock();
+}
+
+static ThreadMap& threadMap()
+{
+ DEFINE_STATIC_LOCAL(ThreadMap, map, ());
+ return map;
+}
+
+static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
+{
+ MutexLocker locker(threadMapMutex());
+
+ ThreadMap::iterator i = threadMap().begin();
+ for (; i != threadMap().end(); ++i) {
+ if (pthread_equal(i->second, pthreadHandle))
+ return i->first;
+ }
+
+ return 0;
+}
+
+static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
+{
+ ASSERT(!identifierByPthreadHandle(pthreadHandle));
+
+ MutexLocker locker(threadMapMutex());
+
+ static ThreadIdentifier identifierCount = 1;
+
+ threadMap().add(identifierCount, pthreadHandle);
+
+ return identifierCount++;
+}
+
+static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ return threadMap().get(id);
+}
+
+void clearPthreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ ASSERT(threadMap().contains(id));
+
+ threadMap().remove(id);
+}
+
+#if PLATFORM(BLACKBERRY)
+ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
+{
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr)) {
+ LOG_ERROR("pthread_attr_init() failed: %d", errno);
+ return 0;
+ }
+
+ void* stackAddr;
+ size_t stackSize;
+ if (pthread_attr_getstack(&attr, &stackAddr, &stackSize))
+ LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
+ else {
+ stackSize = BlackBerry::Platform::Settings::get()->secondaryThreadStackSize();
+ if (pthread_attr_setstack(&attr, stackAddr, stackSize))
+ LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
+ }
+
+ pthread_t threadHandle;
+ if (pthread_create(&threadHandle, &attr, entryPoint, data)) {
+ LOG_ERROR("pthread_create() failed: %d", errno);
+ threadHandle = 0;
+ }
+ pthread_setname_np(threadHandle, threadName);
+
+ pthread_attr_destroy(&attr);
+
+ if (!threadHandle)
+ return 0;
+
+ return establishIdentifierForPthreadHandle(threadHandle);
+}
+#else
+ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
+{
+ pthread_t threadHandle;
+ if (pthread_create(&threadHandle, 0, entryPoint, data)) {
+ LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
+ return 0;
+ }
+
+ return establishIdentifierForPthreadHandle(threadHandle);
+}
+#endif
+
+void initializeCurrentThreadInternal(const char* threadName)
+{
+#if HAVE(PTHREAD_SETNAME_NP)
+ pthread_setname_np(threadName);
+#else
+ UNUSED_PARAM(threadName);
+#endif
+
+#if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
+ // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
+ // garbage collector in case API implementations use garbage-collected memory.
+ objc_registerThreadWithCollector();
+#endif
+
+ ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
+ ASSERT(id);
+ ThreadIdentifierData::initialize(id);
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+ ASSERT(threadID);
+
+ pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
+ if (!pthreadHandle)
+ return 0;
+
+ int joinResult = pthread_join(pthreadHandle, result);
+ if (joinResult == EDEADLK)
+ LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
+
+ return joinResult;
+}
+
+void detachThread(ThreadIdentifier threadID)
+{
+ ASSERT(threadID);
+
+ pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
+ if (!pthreadHandle)
+ return;
+
+ pthread_detach(pthreadHandle);
+}
+
+void yield()
+{
+ sched_yield();
+}
+
+ThreadIdentifier currentThread()
+{
+ ThreadIdentifier id = ThreadIdentifierData::identifier();
+ if (id)
+ return id;
+
+ // Not a WTF-created thread, ThreadIdentifier is not established yet.
+ id = establishIdentifierForPthreadHandle(pthread_self());
+ ThreadIdentifierData::initialize(id);
+ return id;
+}
+
+Mutex::Mutex()
+{
+ 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()
+{
+ pthread_mutex_destroy(&m_mutex);
+}
+
+void Mutex::lock()
+{
+ int result = pthread_mutex_lock(&m_mutex);
+ ASSERT_UNUSED(result, !result);
+}
+
+bool Mutex::tryLock()
+{
+ int result = pthread_mutex_trylock(&m_mutex);
+
+ if (result == 0)
+ return true;
+ if (result == EBUSY)
+ return false;
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void Mutex::unlock()
+{
+ int result = pthread_mutex_unlock(&m_mutex);
+ ASSERT_UNUSED(result, !result);
+}
+
+#if HAVE(PTHREAD_RWLOCK)
+ReadWriteLock::ReadWriteLock()
+{
+ pthread_rwlock_init(&m_readWriteLock, NULL);
+}
+
+ReadWriteLock::~ReadWriteLock()
+{
+ pthread_rwlock_destroy(&m_readWriteLock);
+}
+
+void ReadWriteLock::readLock()
+{
+ int result = pthread_rwlock_rdlock(&m_readWriteLock);
+ ASSERT_UNUSED(result, !result);
+}
+
+bool ReadWriteLock::tryReadLock()
+{
+ int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
+
+ if (result == 0)
+ return true;
+ if (result == EBUSY || result == EAGAIN)
+ return false;
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void ReadWriteLock::writeLock()
+{
+ int result = pthread_rwlock_wrlock(&m_readWriteLock);
+ ASSERT_UNUSED(result, !result);
+}
+
+bool ReadWriteLock::tryWriteLock()
+{
+ int result = pthread_rwlock_trywrlock(&m_readWriteLock);
+
+ if (result == 0)
+ return true;
+ if (result == EBUSY || result == EAGAIN)
+ return false;
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void ReadWriteLock::unlock()
+{
+ int result = pthread_rwlock_unlock(&m_readWriteLock);
+ ASSERT_UNUSED(result, !result);
+}
+#endif // HAVE(PTHREAD_RWLOCK)
+
+ThreadCondition::ThreadCondition()
+{
+ pthread_cond_init(&m_condition, NULL);
+}
+
+ThreadCondition::~ThreadCondition()
+{
+ pthread_cond_destroy(&m_condition);
+}
+
+void ThreadCondition::wait(Mutex& mutex)
+{
+ int result = pthread_cond_wait(&m_condition, &mutex.impl());
+ ASSERT_UNUSED(result, !result);
+}
+
+bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
+{
+ if (absoluteTime < currentTime())
+ return false;
+
+ if (absoluteTime > INT_MAX) {
+ wait(mutex);
+ return true;
+ }
+
+ int timeSeconds = static_cast<int>(absoluteTime);
+ int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
+
+ timespec targetTime;
+ targetTime.tv_sec = timeSeconds;
+ targetTime.tv_nsec = timeNanoseconds;
+
+ return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
+}
+
+void ThreadCondition::signal()
+{
+ int result = pthread_cond_signal(&m_condition);
+ ASSERT_UNUSED(result, !result);
+}
+
+void ThreadCondition::broadcast()
+{
+ int result = pthread_cond_broadcast(&m_condition);
+ ASSERT_UNUSED(result, !result);
+}
+
+} // namespace WTF
+
+#endif // USE(PTHREADS)
diff --git a/Source/JavaScriptCore/wtf/ThreadingWin.cpp b/Source/JavaScriptCore/wtf/ThreadingWin.cpp
new file mode 100644
index 000000000..ac0f73f19
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ThreadingWin.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, 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.
+ */
+
+/*
+ * There are numerous academic and practical works on how to implement pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast
+ * functions on Win32. Here is one example: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html which is widely credited as a 'starting point'
+ * of modern attempts. There are several more or less proven implementations, one in Boost C++ library (http://www.boost.org) and another
+ * in pthreads-win32 (http://sourceware.org/pthreads-win32/).
+ *
+ * The number of articles and discussions is the evidence of significant difficulties in implementing these primitives correctly.
+ * The brief search of revisions, ChangeLog entries, discussions in comp.programming.threads and other places clearly documents
+ * numerous pitfalls and performance problems the authors had to overcome to arrive to the suitable implementations.
+ * Optimally, WebKit would use one of those supported/tested libraries directly. To roll out our own implementation is impractical,
+ * if even for the lack of sufficient testing. However, a faithful reproduction of the code from one of the popular supported
+ * libraries seems to be a good compromise.
+ *
+ * The early Boost implementation (http://www.boxbackup.org/trac/browser/box/nick/win/lib/win32/boost_1_32_0/libs/thread/src/condition.cpp?rev=30)
+ * is identical to pthreads-win32 (http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1.10&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32).
+ * Current Boost uses yet another (although seemingly equivalent) algorithm which came from their 'thread rewrite' effort.
+ *
+ * This file includes timedWait/signal/broadcast implementations translated to WebKit coding style from the latest algorithm by
+ * Alexander Terekhov and Louis Thomas, as captured here: http://sourceware.org/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_wait.c?rev=1.10&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32
+ * It replaces the implementation of their previous algorithm, also documented in the same source above.
+ * The naming and comments are left very close to original to enable easy cross-check.
+ *
+ * The corresponding Pthreads-win32 License is included below, and CONTRIBUTORS file which it refers to is added to
+ * source directory (as CONTRIBUTORS.pthreads-win32).
+ */
+
+/*
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * 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 in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "config.h"
+#include "Threading.h"
+#include "DateMath.h"
+#include "dtoa.h"
+#include "dtoa/cached-powers.h"
+
+#include "MainThread.h"
+#include "ThreadFunctionInvocation.h"
+#include <windows.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashMap.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RandomNumberSeed.h>
+#include <wtf/WTFThreadData.h>
+
+#if !USE(PTHREADS) && OS(WINDOWS)
+#include "ThreadSpecific.h"
+#endif
+
+#if !OS(WINCE)
+#include <process.h>
+#endif
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+namespace WTF {
+
+// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
+static const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push, 8)
+typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; // must be 0x1000
+ LPCSTR szName; // pointer to name (in user addr space)
+ DWORD dwThreadID; // thread ID (-1=caller thread)
+ DWORD dwFlags; // reserved for future use, must be zero
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+void initializeCurrentThreadInternal(const char* szThreadName)
+{
+#if COMPILER(MINGW)
+ // FIXME: Implement thread name setting with MingW.
+ UNUSED_PARAM(szThreadName);
+#else
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = GetCurrentThreadId();
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
+ } __except (EXCEPTION_CONTINUE_EXECUTION) {
+ }
+#endif
+}
+
+static Mutex* atomicallyInitializedStaticMutex;
+
+void lockAtomicallyInitializedStaticMutex()
+{
+ ASSERT(atomicallyInitializedStaticMutex);
+ atomicallyInitializedStaticMutex->lock();
+}
+
+void unlockAtomicallyInitializedStaticMutex()
+{
+ atomicallyInitializedStaticMutex->unlock();
+}
+
+static Mutex& threadMapMutex()
+{
+ static Mutex mutex;
+ return mutex;
+}
+
+void initializeThreading()
+{
+ if (atomicallyInitializedStaticMutex)
+ return;
+
+ WTF::double_conversion::initialize();
+ // StringImpl::empty() does not construct its static string in a threadsafe fashion,
+ // so ensure it has been initialized from here.
+ StringImpl::empty();
+ atomicallyInitializedStaticMutex = new Mutex;
+ threadMapMutex();
+ initializeRandomNumberGenerator();
+ wtfThreadData();
+ s_dtoaP5Mutex = new Mutex;
+ initializeDates();
+}
+
+static HashMap<DWORD, HANDLE>& threadMap()
+{
+ static HashMap<DWORD, HANDLE> map;
+ return map;
+}
+
+static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
+{
+ MutexLocker locker(threadMapMutex());
+ ASSERT(!threadMap().contains(threadID));
+ threadMap().add(threadID, threadHandle);
+}
+
+static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+ return threadMap().get(id);
+}
+
+static void clearThreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+ ASSERT(threadMap().contains(id));
+ threadMap().remove(id);
+}
+
+static unsigned __stdcall wtfThreadEntryPoint(void* param)
+{
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
+ void* result = invocation->function(invocation->data);
+
+#if !USE(PTHREADS) && OS(WINDOWS)
+ // Do the TLS cleanup.
+ ThreadSpecificThreadExit();
+#endif
+
+ return reinterpret_cast<unsigned>(result);
+}
+
+ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
+{
+ unsigned threadIdentifier = 0;
+ ThreadIdentifier threadID = 0;
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
+#if OS(WINCE)
+ // This is safe on WINCE, since CRT is in the core and innately multithreaded.
+ // On desktop Windows, need to use _beginthreadex (not available on WinCE) if using any CRT functions
+ HANDLE threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)wtfThreadEntryPoint, invocation.get(), 0, (LPDWORD)&threadIdentifier);
+#else
+ HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation.get(), 0, &threadIdentifier));
+#endif
+ if (!threadHandle) {
+#if OS(WINCE)
+ LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, ::GetLastError());
+#elif !HAVE(ERRNO_H)
+ LOG_ERROR("Failed to create thread at entry point %p with data %p.", entryPoint, data);
+#else
+ LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
+#endif
+ return 0;
+ }
+
+ // The thread will take ownership of invocation.
+ invocation.leakPtr();
+
+ threadID = static_cast<ThreadIdentifier>(threadIdentifier);
+ storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
+
+ return threadID;
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+ ASSERT(threadID);
+
+ HANDLE threadHandle = threadHandleForIdentifier(threadID);
+ if (!threadHandle)
+ LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
+
+ DWORD joinResult = WaitForSingleObject(threadHandle, INFINITE);
+ if (joinResult == WAIT_FAILED)
+ LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
+
+ CloseHandle(threadHandle);
+ clearThreadHandleForIdentifier(threadID);
+
+ return joinResult;
+}
+
+void detachThread(ThreadIdentifier threadID)
+{
+ ASSERT(threadID);
+
+ HANDLE threadHandle = threadHandleForIdentifier(threadID);
+ if (threadHandle)
+ CloseHandle(threadHandle);
+ clearThreadHandleForIdentifier(threadID);
+}
+
+void yield()
+{
+ ::Sleep(1);
+}
+
+ThreadIdentifier currentThread()
+{
+ return static_cast<ThreadIdentifier>(GetCurrentThreadId());
+}
+
+Mutex::Mutex()
+{
+ m_mutex.m_recursionCount = 0;
+ InitializeCriticalSection(&m_mutex.m_internalMutex);
+}
+
+Mutex::~Mutex()
+{
+ DeleteCriticalSection(&m_mutex.m_internalMutex);
+}
+
+void Mutex::lock()
+{
+ EnterCriticalSection(&m_mutex.m_internalMutex);
+ ++m_mutex.m_recursionCount;
+}
+
+bool Mutex::tryLock()
+{
+ // This method is modeled after the behavior of pthread_mutex_trylock,
+ // which will return an error if the lock is already owned by the
+ // current thread. Since the primitive Win32 'TryEnterCriticalSection'
+ // treats this as a successful case, it changes the behavior of several
+ // tests in WebKit that check to see if the current thread already
+ // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
+ DWORD result = TryEnterCriticalSection(&m_mutex.m_internalMutex);
+
+ if (result != 0) { // We got the lock
+ // If this thread already had the lock, we must unlock and
+ // return false so that we mimic the behavior of POSIX's
+ // pthread_mutex_trylock:
+ if (m_mutex.m_recursionCount > 0) {
+ LeaveCriticalSection(&m_mutex.m_internalMutex);
+ return false;
+ }
+
+ ++m_mutex.m_recursionCount;
+ return true;
+ }
+
+ return false;
+}
+
+void Mutex::unlock()
+{
+ --m_mutex.m_recursionCount;
+ LeaveCriticalSection(&m_mutex.m_internalMutex);
+}
+
+bool PlatformCondition::timedWait(PlatformMutex& mutex, DWORD durationMilliseconds)
+{
+ // Enter the wait state.
+ DWORD res = WaitForSingleObject(m_blockLock, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ ++m_waitersBlocked;
+ res = ReleaseSemaphore(m_blockLock, 1, 0);
+ ASSERT(res);
+
+ --mutex.m_recursionCount;
+ LeaveCriticalSection(&mutex.m_internalMutex);
+
+ // Main wait - use timeout.
+ bool timedOut = (WaitForSingleObject(m_blockQueue, durationMilliseconds) == WAIT_TIMEOUT);
+
+ res = WaitForSingleObject(m_unblockLock, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+
+ int signalsLeft = m_waitersToUnblock;
+
+ if (m_waitersToUnblock)
+ --m_waitersToUnblock;
+ else if (++m_waitersGone == (INT_MAX / 2)) { // timeout/canceled or spurious semaphore
+ // timeout or spurious wakeup occured, normalize the m_waitersGone count
+ // this may occur if many calls to wait with a timeout are made and
+ // no call to notify_* is made
+ res = WaitForSingleObject(m_blockLock, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ m_waitersBlocked -= m_waitersGone;
+ res = ReleaseSemaphore(m_blockLock, 1, 0);
+ ASSERT(res);
+ m_waitersGone = 0;
+ }
+
+ res = ReleaseMutex(m_unblockLock);
+ ASSERT(res);
+
+ if (signalsLeft == 1) {
+ res = ReleaseSemaphore(m_blockLock, 1, 0); // Open the gate.
+ ASSERT(res);
+ }
+
+ EnterCriticalSection (&mutex.m_internalMutex);
+ ++mutex.m_recursionCount;
+
+ return !timedOut;
+}
+
+void PlatformCondition::signal(bool unblockAll)
+{
+ unsigned signalsToIssue = 0;
+
+ DWORD res = WaitForSingleObject(m_unblockLock, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+
+ if (m_waitersToUnblock) { // the gate is already closed
+ if (!m_waitersBlocked) { // no-op
+ res = ReleaseMutex(m_unblockLock);
+ ASSERT(res);
+ return;
+ }
+
+ if (unblockAll) {
+ signalsToIssue = m_waitersBlocked;
+ m_waitersToUnblock += m_waitersBlocked;
+ m_waitersBlocked = 0;
+ } else {
+ signalsToIssue = 1;
+ ++m_waitersToUnblock;
+ --m_waitersBlocked;
+ }
+ } else if (m_waitersBlocked > m_waitersGone) {
+ res = WaitForSingleObject(m_blockLock, INFINITE); // Close the gate.
+ ASSERT(res == WAIT_OBJECT_0);
+ if (m_waitersGone != 0) {
+ m_waitersBlocked -= m_waitersGone;
+ m_waitersGone = 0;
+ }
+ if (unblockAll) {
+ signalsToIssue = m_waitersBlocked;
+ m_waitersToUnblock = m_waitersBlocked;
+ m_waitersBlocked = 0;
+ } else {
+ signalsToIssue = 1;
+ m_waitersToUnblock = 1;
+ --m_waitersBlocked;
+ }
+ } else { // No-op.
+ res = ReleaseMutex(m_unblockLock);
+ ASSERT(res);
+ return;
+ }
+
+ res = ReleaseMutex(m_unblockLock);
+ ASSERT(res);
+
+ if (signalsToIssue) {
+ res = ReleaseSemaphore(m_blockQueue, signalsToIssue, 0);
+ ASSERT(res);
+ }
+}
+
+static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
+
+ThreadCondition::ThreadCondition()
+{
+ m_condition.m_waitersGone = 0;
+ m_condition.m_waitersBlocked = 0;
+ m_condition.m_waitersToUnblock = 0;
+ m_condition.m_blockLock = CreateSemaphore(0, 1, 1, 0);
+ m_condition.m_blockQueue = CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
+ m_condition.m_unblockLock = CreateMutex(0, 0, 0);
+
+ if (!m_condition.m_blockLock || !m_condition.m_blockQueue || !m_condition.m_unblockLock) {
+ if (m_condition.m_blockLock)
+ CloseHandle(m_condition.m_blockLock);
+ if (m_condition.m_blockQueue)
+ CloseHandle(m_condition.m_blockQueue);
+ if (m_condition.m_unblockLock)
+ CloseHandle(m_condition.m_unblockLock);
+ }
+}
+
+ThreadCondition::~ThreadCondition()
+{
+ CloseHandle(m_condition.m_blockLock);
+ CloseHandle(m_condition.m_blockQueue);
+ CloseHandle(m_condition.m_unblockLock);
+}
+
+void ThreadCondition::wait(Mutex& mutex)
+{
+ m_condition.timedWait(mutex.impl(), INFINITE);
+}
+
+bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
+{
+ DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
+
+ if (!interval) {
+ // Consider the wait to have timed out, even if our condition has already been signaled, to
+ // match the pthreads implementation.
+ return false;
+ }
+
+ return m_condition.timedWait(mutex.impl(), interval);
+}
+
+void ThreadCondition::signal()
+{
+ m_condition.signal(false); // Unblock only 1 thread.
+}
+
+void ThreadCondition::broadcast()
+{
+ m_condition.signal(true); // Unblock all threads.
+}
+
+DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime)
+{
+ double currentTime = WTF::currentTime();
+
+ // Time is in the past - return immediately.
+ if (absoluteTime < currentTime)
+ return 0;
+
+ // Time is too far in the future (and would overflow unsigned long) - wait forever.
+ if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0)
+ return INFINITE;
+
+ return static_cast<DWORD>((absoluteTime - currentTime) * 1000.0);
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/TypeTraits.cpp b/Source/JavaScriptCore/wtf/TypeTraits.cpp
new file mode 100644
index 000000000..afeaa5e4c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TypeTraits.cpp
@@ -0,0 +1,142 @@
+ /*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "TypeTraits.h"
+
+#include "Assertions.h"
+
+namespace WTF {
+
+COMPILE_ASSERT(IsInteger<bool>::value, WTF_IsInteger_bool_true);
+COMPILE_ASSERT(IsInteger<char>::value, WTF_IsInteger_char_true);
+COMPILE_ASSERT(IsInteger<signed char>::value, WTF_IsInteger_signed_char_true);
+COMPILE_ASSERT(IsInteger<unsigned char>::value, WTF_IsInteger_unsigned_char_true);
+COMPILE_ASSERT(IsInteger<short>::value, WTF_IsInteger_short_true);
+COMPILE_ASSERT(IsInteger<unsigned short>::value, WTF_IsInteger_unsigned_short_true);
+COMPILE_ASSERT(IsInteger<int>::value, WTF_IsInteger_int_true);
+COMPILE_ASSERT(IsInteger<unsigned int>::value, WTF_IsInteger_unsigned_int_true);
+COMPILE_ASSERT(IsInteger<long>::value, WTF_IsInteger_long_true);
+COMPILE_ASSERT(IsInteger<unsigned long>::value, WTF_IsInteger_unsigned_long_true);
+COMPILE_ASSERT(IsInteger<long long>::value, WTF_IsInteger_long_long_true);
+COMPILE_ASSERT(IsInteger<unsigned long long>::value, WTF_IsInteger_unsigned_long_long_true);
+#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
+COMPILE_ASSERT(IsInteger<wchar_t>::value, WTF_IsInteger_wchar_t_true);
+#endif
+COMPILE_ASSERT(!IsInteger<char*>::value, WTF_IsInteger_char_pointer_false);
+COMPILE_ASSERT(!IsInteger<const char*>::value, WTF_IsInteger_const_char_pointer_false);
+COMPILE_ASSERT(!IsInteger<volatile char*>::value, WTF_IsInteger_volatile_char_pointer_false);
+COMPILE_ASSERT(!IsInteger<double>::value, WTF_IsInteger_double_false);
+COMPILE_ASSERT(!IsInteger<float>::value, WTF_IsInteger_float_false);
+
+COMPILE_ASSERT(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);
+COMPILE_ASSERT(IsPod<unsigned char>::value, WTF_IsPod_unsigned_char_true);
+COMPILE_ASSERT(IsPod<short>::value, WTF_IsPod_short_true);
+COMPILE_ASSERT(IsPod<unsigned short>::value, WTF_IsPod_unsigned_short_true);
+COMPILE_ASSERT(IsPod<int>::value, WTF_IsPod_int_true);
+COMPILE_ASSERT(IsPod<unsigned int>::value, WTF_IsPod_unsigned_int_true);
+COMPILE_ASSERT(IsPod<long>::value, WTF_IsPod_long_true);
+COMPILE_ASSERT(IsPod<unsigned long>::value, WTF_IsPod_unsigned_long_true);
+COMPILE_ASSERT(IsPod<long long>::value, WTF_IsPod_long_long_true);
+COMPILE_ASSERT(IsPod<unsigned long long>::value, WTF_IsPod_unsigned_long_long_true);
+#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
+COMPILE_ASSERT(IsPod<wchar_t>::value, WTF_IsPod_wchar_t_true);
+#endif
+COMPILE_ASSERT(IsPod<char*>::value, WTF_IsPod_char_pointer_true);
+COMPILE_ASSERT(IsPod<const char*>::value, WTF_IsPod_const_char_pointer_true);
+COMPILE_ASSERT(IsPod<volatile char*>::value, WTF_IsPod_volatile_char_pointer_true);
+COMPILE_ASSERT(IsPod<double>::value, WTF_IsPod_double_true);
+COMPILE_ASSERT(IsPod<long double>::value, WTF_IsPod_long_double_true);
+COMPILE_ASSERT(IsPod<float>::value, WTF_IsPod_float_true);
+COMPILE_ASSERT(!IsPod<IsPod<bool> >::value, WTF_IsPod_struct_false);
+
+enum IsConvertibleToIntegerCheck { };
+COMPILE_ASSERT(IsConvertibleToInteger<IsConvertibleToIntegerCheck>::value, WTF_IsConvertibleToInteger_enum_true);
+COMPILE_ASSERT(IsConvertibleToInteger<bool>::value, WTF_IsConvertibleToInteger_bool_true);
+COMPILE_ASSERT(IsConvertibleToInteger<char>::value, WTF_IsConvertibleToInteger_char_true);
+COMPILE_ASSERT(IsConvertibleToInteger<signed char>::value, WTF_IsConvertibleToInteger_signed_char_true);
+COMPILE_ASSERT(IsConvertibleToInteger<unsigned char>::value, WTF_IsConvertibleToInteger_unsigned_char_true);
+COMPILE_ASSERT(IsConvertibleToInteger<short>::value, WTF_IsConvertibleToInteger_short_true);
+COMPILE_ASSERT(IsConvertibleToInteger<unsigned short>::value, WTF_IsConvertibleToInteger_unsigned_short_true);
+COMPILE_ASSERT(IsConvertibleToInteger<int>::value, WTF_IsConvertibleToInteger_int_true);
+COMPILE_ASSERT(IsConvertibleToInteger<unsigned int>::value, WTF_IsConvertibleToInteger_unsigned_int_true);
+COMPILE_ASSERT(IsConvertibleToInteger<long>::value, WTF_IsConvertibleToInteger_long_true);
+COMPILE_ASSERT(IsConvertibleToInteger<unsigned long>::value, WTF_IsConvertibleToInteger_unsigned_long_true);
+COMPILE_ASSERT(IsConvertibleToInteger<long long>::value, WTF_IsConvertibleToInteger_long_long_true);
+COMPILE_ASSERT(IsConvertibleToInteger<unsigned long long>::value, WTF_IsConvertibleToInteger_unsigned_long_long_true);
+#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
+COMPILE_ASSERT(IsConvertibleToInteger<wchar_t>::value, WTF_IsConvertibleToInteger_wchar_t_true);
+#endif
+COMPILE_ASSERT(IsConvertibleToInteger<double>::value, WTF_IsConvertibleToInteger_double_true);
+COMPILE_ASSERT(IsConvertibleToInteger<long double>::value, WTF_IsConvertibleToInteger_long_double_true);
+COMPILE_ASSERT(IsConvertibleToInteger<float>::value, WTF_IsConvertibleToInteger_float_true);
+COMPILE_ASSERT(!IsConvertibleToInteger<char*>::value, WTF_IsConvertibleToInteger_char_pointer_false);
+COMPILE_ASSERT(!IsConvertibleToInteger<const char*>::value, WTF_IsConvertibleToInteger_const_char_pointer_false);
+COMPILE_ASSERT(!IsConvertibleToInteger<volatile char*>::value, WTF_IsConvertibleToInteger_volatile_char_pointer_false);
+COMPILE_ASSERT(!IsConvertibleToInteger<IsConvertibleToInteger<bool> >::value, WTF_IsConvertibleToInteger_struct_false);
+
+COMPILE_ASSERT((IsSameType<bool, bool>::value), WTF_IsSameType_bool_true);
+COMPILE_ASSERT((IsSameType<int*, int*>::value), WTF_IsSameType_int_pointer_true);
+COMPILE_ASSERT((!IsSameType<int, int*>::value), WTF_IsSameType_int_int_pointer_false);
+COMPILE_ASSERT((!IsSameType<bool, const bool>::value), WTF_IsSameType_const_change_false);
+COMPILE_ASSERT((!IsSameType<bool, volatile bool>::value), WTF_IsSameType_volatile_change_false);
+
+template <typename T>
+class TestBaseClass {
+};
+
+class TestDerivedClass : public TestBaseClass<int> {
+};
+
+COMPILE_ASSERT((IsSubclass<TestDerivedClass, TestBaseClass<int> >::value), WTF_Test_IsSubclass_Derived_From_Base);
+COMPILE_ASSERT((!IsSubclass<TestBaseClass<int>, TestDerivedClass>::value), WTF_Test_IsSubclass_Base_From_Derived);
+COMPILE_ASSERT((IsSubclassOfTemplate<TestDerivedClass, TestBaseClass>::value), WTF_Test_IsSubclassOfTemplate_Base_From_Derived);
+COMPILE_ASSERT((IsSameType<RemoveTemplate<TestBaseClass<int>, TestBaseClass>::Type, int>::value), WTF_Test_RemoveTemplate);
+COMPILE_ASSERT((IsSameType<RemoveTemplate<int, TestBaseClass>::Type, int>::value), WTF_Test_RemoveTemplate_WithoutTemplate);
+
+
+COMPILE_ASSERT((IsSameType<bool, RemoveConst<const bool>::Type>::value), WTF_test_RemoveConst_const_bool);
+COMPILE_ASSERT((!IsSameType<bool, RemoveConst<volatile bool>::Type>::value), WTF_test_RemoveConst_volatile_bool);
+
+COMPILE_ASSERT((IsSameType<bool, RemoveVolatile<bool>::Type>::value), WTF_test_RemoveVolatile_bool);
+COMPILE_ASSERT((!IsSameType<bool, RemoveVolatile<const bool>::Type>::value), WTF_test_RemoveVolatile_const_bool);
+COMPILE_ASSERT((IsSameType<bool, RemoveVolatile<volatile bool>::Type>::value), WTF_test_RemoveVolatile_volatile_bool);
+
+COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<bool>::Type>::value), WTF_test_RemoveConstVolatile_bool);
+COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<const bool>::Type>::value), WTF_test_RemoveConstVolatile_const_bool);
+COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<volatile bool>::Type>::value), WTF_test_RemoveConstVolatile_volatile_bool);
+COMPILE_ASSERT((IsSameType<bool, RemoveConstVolatile<const volatile bool>::Type>::value), WTF_test_RemoveConstVolatile_const_volatile_bool);
+
+COMPILE_ASSERT((IsSameType<int, RemovePointer<int>::Type>::value), WTF_Test_RemovePointer_int);
+COMPILE_ASSERT((IsSameType<int, RemovePointer<int*>::Type>::value), WTF_Test_RemovePointer_int_pointer);
+COMPILE_ASSERT((!IsSameType<int, RemovePointer<int**>::Type>::value), WTF_Test_RemovePointer_int_pointer_pointer);
+
+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/Source/JavaScriptCore/wtf/TypeTraits.h b/Source/JavaScriptCore/wtf/TypeTraits.h
new file mode 100644
index 000000000..6c7466acc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TypeTraits.h
@@ -0,0 +1,389 @@
+ /*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TypeTraits_h
+#define TypeTraits_h
+
+#include "Platform.h"
+
+#if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
+#include <type_traits>
+#if defined(__GXX_EXPERIMENTAL_CXX0X__)
+#include <tr1/memory>
+#endif
+#endif
+
+namespace WTF {
+
+ // The following are provided in this file:
+ //
+ // IsInteger<T>::value
+ // IsPod<T>::value, see the definition for a note about its limitations
+ // IsConvertibleToInteger<T>::value
+ //
+ // IsSameType<T, U>::value
+ //
+ // RemovePointer<T>::Type
+ // RemoveReference<T>::Type
+ // RemoveConst<T>::Type
+ // RemoveVolatile<T>::Type
+ // RemoveConstVolatile<T>::Type
+ //
+ // COMPILE_ASSERT's in TypeTraits.cpp illustrate their usage and what they do.
+
+ template<typename T> struct IsInteger { static const bool value = false; };
+ template<> struct IsInteger<bool> { static const bool value = true; };
+ template<> struct IsInteger<char> { static const bool value = true; };
+ template<> struct IsInteger<signed char> { static const bool value = true; };
+ template<> struct IsInteger<unsigned char> { static const bool value = true; };
+ template<> struct IsInteger<short> { static const bool value = true; };
+ template<> struct IsInteger<unsigned short> { static const bool value = true; };
+ template<> struct IsInteger<int> { static const bool value = true; };
+ template<> struct IsInteger<unsigned int> { static const bool value = true; };
+ template<> struct IsInteger<long> { static const bool value = true; };
+ template<> struct IsInteger<unsigned long> { static const bool value = true; };
+ template<> struct IsInteger<long long> { static const bool value = true; };
+ template<> struct IsInteger<unsigned long long> { static const bool value = true; };
+#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
+ template<> struct IsInteger<wchar_t> { static const bool value = true; };
+#endif
+
+ 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 = IsArithmetic<T>::value; };
+ template <typename P> struct IsPod<P*> { static const bool value = true; };
+
+ template<typename T> class IsConvertibleToInteger {
+ // Avoid "possible loss of data" warning when using Microsoft's C++ compiler
+ // by not converting int's to doubles.
+ template<bool performCheck, typename U> class IsConvertibleToDouble;
+ template<typename U> class IsConvertibleToDouble<false, U> {
+ public:
+ static const bool value = false;
+ };
+
+ template<typename U> class IsConvertibleToDouble<true, U> {
+ typedef char YesType;
+ struct NoType {
+ char padding[8];
+ };
+
+ static YesType floatCheck(long double);
+ static NoType floatCheck(...);
+ static T& t;
+ public:
+ static const bool value = sizeof(floatCheck(t)) == sizeof(YesType);
+ };
+
+ public:
+ static const bool value = IsInteger<T>::value || IsConvertibleToDouble<!IsInteger<T>::value, T>::value;
+ };
+
+ template <typename T, typename U> struct IsSameType {
+ static const bool value = false;
+ };
+
+ template <typename T> struct IsSameType<T, T> {
+ static const bool value = true;
+ };
+
+ template <typename T, typename U> class IsSubclass {
+ typedef char YesType;
+ struct NoType {
+ char padding[8];
+ };
+
+ static YesType subclassCheck(U*);
+ static NoType subclassCheck(...);
+ static T* t;
+ public:
+ static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
+ };
+
+ template <typename T, template<class V> class U> class IsSubclassOfTemplate {
+ typedef char YesType;
+ struct NoType {
+ char padding[8];
+ };
+
+ template<typename W> static YesType subclassCheck(U<W>*);
+ static NoType subclassCheck(...);
+ static T* t;
+ public:
+ static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
+ };
+
+ template <typename T, template <class V> class OuterTemplate> struct RemoveTemplate {
+ typedef T Type;
+ };
+
+ template <typename T, template <class V> class OuterTemplate> struct RemoveTemplate<OuterTemplate<T>, OuterTemplate> {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveConst {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveConst<const T> {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveVolatile {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveVolatile<volatile T> {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveConstVolatile {
+ typedef typename RemoveVolatile<typename RemoveConst<T>::Type>::Type Type;
+ };
+
+ template <typename T> struct RemovePointer {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemovePointer<T*> {
+ typedef T Type;
+ };
+
+ 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.
+ // VC10 (VS2010) and later support C++ TR1 type_traits in the std::tr1 namespace.
+ template<typename T> struct HasTrivialConstructor : public std::tr1::has_trivial_constructor<T> { };
+ template<typename T> struct HasTrivialDestructor : public std::tr1::has_trivial_destructor<T> { };
+
+#else
+
+ // This compiler doesn't provide type traits, so we provide basic HasTrivialConstructor
+ // and HasTrivialDestructor definitions. The definitions here include most built-in
+ // scalar types but do not include POD structs and classes. For the intended purposes of
+ // type_traits this results correct but potentially less efficient code.
+ template <typename T, T v>
+ struct IntegralConstant {
+ static const T value = v;
+ typedef T value_type;
+ typedef IntegralConstant<T, v> type;
+ };
+
+ typedef IntegralConstant<bool, true> true_type;
+ typedef IntegralConstant<bool, false> false_type;
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER)
+ // VC8 (VS2005) and later have built-in compiler support for HasTrivialConstructor / HasTrivialDestructor,
+ // but for some unexplained reason it doesn't work on built-in types.
+ template <typename T> struct HasTrivialConstructor : public IntegralConstant<bool, __has_trivial_constructor(T)>{ };
+ template <typename T> struct HasTrivialDestructor : public IntegralConstant<bool, __has_trivial_destructor(T)>{ };
+#else
+ template <typename T> struct HasTrivialConstructor : public false_type{ };
+ template <typename T> struct HasTrivialDestructor : public false_type{ };
+#endif
+
+ template <typename T> struct HasTrivialConstructor<T*> : public true_type{ };
+ template <typename T> struct HasTrivialDestructor<T*> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<float> : public true_type{ };
+ template <> struct HasTrivialConstructor<const float> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile float> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile float> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<double> : public true_type{ };
+ template <> struct HasTrivialConstructor<const double> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile double> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile double> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<long double> : public true_type{ };
+ template <> struct HasTrivialConstructor<const long double> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile long double> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile long double> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<unsigned char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const unsigned char> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile unsigned char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile unsigned char> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<unsigned short> : public true_type{ };
+ template <> struct HasTrivialConstructor<const unsigned short> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile unsigned short> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile unsigned short> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<unsigned int> : public true_type{ };
+ template <> struct HasTrivialConstructor<const unsigned int> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile unsigned int> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile unsigned int> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<unsigned long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const unsigned long> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile unsigned long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile unsigned long> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<unsigned long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const unsigned long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile unsigned long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile unsigned long long> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<signed char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const signed char> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile signed char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile signed char> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<signed short> : public true_type{ };
+ template <> struct HasTrivialConstructor<const signed short> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile signed short> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile signed short> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<signed int> : public true_type{ };
+ template <> struct HasTrivialConstructor<const signed int> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile signed int> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile signed int> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<signed long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const signed long> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile signed long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile signed long> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<signed long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const signed long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile signed long long> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile signed long long> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<bool> : public true_type{ };
+ template <> struct HasTrivialConstructor<const bool> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile bool> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile bool> : public true_type{ };
+
+ template <> struct HasTrivialConstructor<char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const char> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile char> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile char> : public true_type{ };
+
+ #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+ template <> struct HasTrivialConstructor<wchar_t> : public true_type{ };
+ template <> struct HasTrivialConstructor<const wchar_t> : public true_type{ };
+ template <> struct HasTrivialConstructor<volatile wchar_t> : public true_type{ };
+ template <> struct HasTrivialConstructor<const volatile wchar_t> : public true_type{ };
+ #endif
+
+ template <> struct HasTrivialDestructor<float> : public true_type{ };
+ template <> struct HasTrivialDestructor<const float> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile float> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile float> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<double> : public true_type{ };
+ template <> struct HasTrivialDestructor<const double> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile double> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile double> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<long double> : public true_type{ };
+ template <> struct HasTrivialDestructor<const long double> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile long double> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile long double> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<unsigned char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const unsigned char> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile unsigned char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile unsigned char> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<unsigned short> : public true_type{ };
+ template <> struct HasTrivialDestructor<const unsigned short> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile unsigned short> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile unsigned short> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<unsigned int> : public true_type{ };
+ template <> struct HasTrivialDestructor<const unsigned int> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile unsigned int> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile unsigned int> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<unsigned long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const unsigned long> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile unsigned long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile unsigned long> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<unsigned long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const unsigned long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile unsigned long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile unsigned long long> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<signed char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const signed char> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile signed char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile signed char> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<signed short> : public true_type{ };
+ template <> struct HasTrivialDestructor<const signed short> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile signed short> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile signed short> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<signed int> : public true_type{ };
+ template <> struct HasTrivialDestructor<const signed int> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile signed int> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile signed int> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<signed long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const signed long> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile signed long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile signed long> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<signed long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const signed long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile signed long long> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile signed long long> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<bool> : public true_type{ };
+ template <> struct HasTrivialDestructor<const bool> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile bool> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile bool> : public true_type{ };
+
+ template <> struct HasTrivialDestructor<char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const char> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile char> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile char> : public true_type{ };
+
+ #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+ template <> struct HasTrivialDestructor<wchar_t> : public true_type{ };
+ template <> struct HasTrivialDestructor<const wchar_t> : public true_type{ };
+ template <> struct HasTrivialDestructor<volatile wchar_t> : public true_type{ };
+ template <> struct HasTrivialDestructor<const volatile wchar_t> : public true_type{ };
+ #endif
+
+#endif // __GLIBCXX__, etc.
+
+} // namespace WTF
+
+#endif // TypeTraits_h
diff --git a/Source/JavaScriptCore/wtf/TypedArrayBase.h b/Source/JavaScriptCore/wtf/TypedArrayBase.h
new file mode 100644
index 000000000..dba95d55f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/TypedArrayBase.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Apple 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:
+ * 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 TypedArrayBase_h
+#define TypedArrayBase_h
+
+#include "ArrayBuffer.h"
+#include "ArrayBufferView.h"
+
+namespace WTF {
+
+template <typename T>
+class TypedArrayBase : public ArrayBufferView {
+ public:
+ T* data() const { return static_cast<T*>(baseAddress()); }
+
+ bool set(TypedArrayBase<T>* array, unsigned offset)
+ {
+ return setImpl(array, offset * sizeof(T));
+ }
+
+ bool setRange(const T* data, size_t dataLength, unsigned offset)
+ {
+ return setRangeImpl(reinterpret_cast<const char*>(data), dataLength * sizeof(T), offset * sizeof(T));
+ }
+
+ bool zeroRange(unsigned offset, size_t length)
+ {
+ return zeroRangeImpl(offset * sizeof(T), length * sizeof(T));
+ }
+
+ // Overridden from ArrayBufferView. This must be public because of
+ // rules about inheritance of members in template classes, and
+ // because it is accessed via pointers to subclasses.
+ unsigned length() const
+ {
+ return m_length;
+ }
+
+ virtual unsigned byteLength() const
+ {
+ return m_length * sizeof(T);
+ }
+
+protected:
+ TypedArrayBase(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : ArrayBufferView(buffer, byteOffset)
+ , m_length(length)
+ {
+ }
+
+ template <class Subclass>
+ static PassRefPtr<Subclass> create(unsigned length)
+ {
+ RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(T));
+ if (!buffer.get())
+ return 0;
+ return create<Subclass>(buffer, 0, length);
+ }
+
+ template <class Subclass>
+ static PassRefPtr<Subclass> create(const T* array, unsigned length)
+ {
+ RefPtr<Subclass> a = create<Subclass>(length);
+ if (a)
+ for (unsigned i = 0; i < length; ++i)
+ a->set(i, array[i]);
+ return a;
+ }
+
+ template <class Subclass>
+ static PassRefPtr<Subclass> create(PassRefPtr<ArrayBuffer> buffer,
+ unsigned byteOffset,
+ unsigned length)
+ {
+ RefPtr<ArrayBuffer> buf(buffer);
+ if (!verifySubRange<T>(buf, byteOffset, length))
+ return 0;
+
+ return adoptRef(new Subclass(buf, byteOffset, length));
+ }
+
+ template <class Subclass>
+ PassRefPtr<Subclass> subarrayImpl(int start, int end) const
+ {
+ unsigned offset, length;
+ calculateOffsetAndLength(start, end, m_length, &offset, &length);
+ clampOffsetAndNumElements<T>(buffer(), m_byteOffset, &offset, &length);
+ return create<Subclass>(buffer(), offset, length);
+ }
+
+ virtual void neuter()
+ {
+ ArrayBufferView::neuter();
+ m_length = 0;
+ }
+
+ // We do not want to have to access this via a virtual function in subclasses,
+ // which is why it is protected rather than private.
+ unsigned m_length;
+};
+
+} // namespace WTF
+
+using WTF::TypedArrayBase;
+
+#endif // TypedArrayBase_h
diff --git a/Source/JavaScriptCore/wtf/Uint16Array.h b/Source/JavaScriptCore/wtf/Uint16Array.h
new file mode 100644
index 000000000..2d0765051
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Uint16Array.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Uint16Array_h
+#define Uint16Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class ArrayBuffer;
+
+class Uint16Array : public IntegralTypedArrayBase<unsigned short> {
+public:
+ static inline PassRefPtr<Uint16Array> create(unsigned length);
+ static inline PassRefPtr<Uint16Array> create(unsigned short* array, unsigned length);
+ static inline PassRefPtr<Uint16Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<unsigned short>* array, unsigned offset) { return TypedArrayBase<unsigned short>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned short>::set(index, value); }
+
+ inline PassRefPtr<Uint16Array> subarray(int start) const;
+ inline PassRefPtr<Uint16Array> subarray(int start, int end) const;
+
+private:
+ inline Uint16Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<unsigned short>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isUnsignedShortArray() const { return true; }
+};
+
+PassRefPtr<Uint16Array> Uint16Array::create(unsigned length)
+{
+ return TypedArrayBase<unsigned short>::create<Uint16Array>(length);
+}
+
+PassRefPtr<Uint16Array> Uint16Array::create(unsigned short* array, unsigned length)
+{
+ return TypedArrayBase<unsigned short>::create<Uint16Array>(array, length);
+}
+
+PassRefPtr<Uint16Array> Uint16Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<unsigned short>::create<Uint16Array>(buffer, byteOffset, length);
+}
+
+Uint16Array::Uint16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : IntegralTypedArrayBase<unsigned short>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Uint16Array> Uint16Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Uint16Array> Uint16Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Uint16Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Uint16Array;
+
+#endif // Uint16Array_h
diff --git a/Source/JavaScriptCore/wtf/Uint32Array.h b/Source/JavaScriptCore/wtf/Uint32Array.h
new file mode 100644
index 000000000..3765f8077
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Uint32Array.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Uint32Array_h
+#define Uint32Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class ArrayBuffer;
+
+class Uint32Array : public IntegralTypedArrayBase<unsigned int> {
+public:
+ static inline PassRefPtr<Uint32Array> create(unsigned length);
+ static inline PassRefPtr<Uint32Array> create(unsigned int* array, unsigned length);
+ static inline PassRefPtr<Uint32Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<unsigned int>* array, unsigned offset) { return TypedArrayBase<unsigned int>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned int>::set(index, value); }
+
+ inline PassRefPtr<Uint32Array> subarray(int start) const;
+ inline PassRefPtr<Uint32Array> subarray(int start, int end) const;
+
+private:
+ inline Uint32Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<unsigned int>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isUnsignedIntArray() const { return true; }
+};
+
+PassRefPtr<Uint32Array> Uint32Array::create(unsigned length)
+{
+ return TypedArrayBase<unsigned int>::create<Uint32Array>(length);
+}
+
+PassRefPtr<Uint32Array> Uint32Array::create(unsigned int* array, unsigned length)
+{
+ return TypedArrayBase<unsigned int>::create<Uint32Array>(array, length);
+}
+
+PassRefPtr<Uint32Array> Uint32Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<unsigned int>::create<Uint32Array>(buffer, byteOffset, length);
+}
+
+Uint32Array::Uint32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ : IntegralTypedArrayBase<unsigned int>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Uint32Array> Uint32Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Uint32Array> Uint32Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Uint32Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Uint32Array;
+
+#endif // Uint32Array_h
diff --git a/Source/JavaScriptCore/wtf/Uint8Array.h b/Source/JavaScriptCore/wtf/Uint8Array.h
new file mode 100644
index 000000000..58fdb842b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Uint8Array.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 Uint8Array_h
+#define Uint8Array_h
+
+#include "IntegralTypedArrayBase.h"
+
+namespace WTF {
+
+class ArrayBuffer;
+
+class Uint8Array : public IntegralTypedArrayBase<unsigned char> {
+public:
+ static inline PassRefPtr<Uint8Array> create(unsigned length);
+ static inline PassRefPtr<Uint8Array> create(unsigned char* array, unsigned length);
+ static inline PassRefPtr<Uint8Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+
+ // Can’t use "using" here due to a bug in the RVCT compiler.
+ bool set(TypedArrayBase<unsigned char>* array, unsigned offset) { return TypedArrayBase<unsigned char>::set(array, offset); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned char>::set(index, value); }
+
+ inline PassRefPtr<Uint8Array> subarray(int start) const;
+ inline PassRefPtr<Uint8Array> subarray(int start, int end) const;
+
+private:
+ inline Uint8Array(PassRefPtr<ArrayBuffer>,
+ unsigned byteOffset,
+ unsigned length);
+ // Make constructor visible to superclass.
+ friend class TypedArrayBase<unsigned char>;
+
+ // Overridden from ArrayBufferView.
+ virtual bool isUnsignedByteArray() const { return true; }
+};
+
+PassRefPtr<Uint8Array> Uint8Array::create(unsigned length)
+{
+ return TypedArrayBase<unsigned char>::create<Uint8Array>(length);
+}
+
+PassRefPtr<Uint8Array> Uint8Array::create(unsigned char* array, unsigned length)
+{
+ return TypedArrayBase<unsigned char>::create<Uint8Array>(array, length);
+}
+
+PassRefPtr<Uint8Array> Uint8Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+{
+ return TypedArrayBase<unsigned char>::create<Uint8Array>(buffer, byteOffset, length);
+}
+
+Uint8Array::Uint8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+: IntegralTypedArrayBase<unsigned char>(buffer, byteOffset, length)
+{
+}
+
+PassRefPtr<Uint8Array> Uint8Array::subarray(int start) const
+{
+ return subarray(start, length());
+}
+
+PassRefPtr<Uint8Array> Uint8Array::subarray(int start, int end) const
+{
+ return subarrayImpl<Uint8Array>(start, end);
+}
+
+} // namespace WTF
+
+using WTF::Uint8Array;
+
+#endif // Uint8Array_h
diff --git a/Source/JavaScriptCore/wtf/UnionFind.h b/Source/JavaScriptCore/wtf/UnionFind.h
new file mode 100644
index 000000000..fa737116c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/UnionFind.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 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 UnionFind_h
+#define UnionFind_h
+
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+// A UnionFind class can be used to compute disjoint sets using the
+// disjoint-set forest data structure. Each UnionFind instance is a
+// node in the forest. Typically you use it by using UnionFind as a
+// superclass:
+//
+// class MemberOfSet : public UnionFind<MemberOfSet> { ... }
+//
+// Calling x->find() gives you a MemberOfSet* that represents the
+// disjoint set that x belongs to. Calling x->unify(y) unifies x's
+// set with y's set, and ensures that:
+//
+// x->find() == y->find()
+//
+// and that:
+//
+// a->find() == b->find()
+//
+// for any a, b if prior to the call to x->unify(y), we would have
+// had:
+//
+// a->find() == x
+// b->find() == y
+//
+// This implementation is almost amortized O(1), but could be worse
+// in unlikely pathological cases. It favors having a non-recursive
+// single pass implementation of unify() and find() over ensuring the
+// theoretical O(InverseAckermann[n]) amortized bound, which is much
+// closer to amortized O(1).
+
+template<typename T>
+class UnionFind {
+public:
+ UnionFind()
+ : m_parent(0)
+ {
+ }
+
+ T* find()
+ {
+ T* result = static_cast<T*>(this);
+ T* next = result->m_parent;
+ while (next) {
+ result = next;
+ next = result->m_parent;
+ }
+ ASSERT(result);
+ if (result != this)
+ m_parent = result;
+ return result;
+ }
+
+ void unify(T* other)
+ {
+ T* a = static_cast<T*>(this)->find();
+ T* b = other->find();
+
+ ASSERT(!a->m_parent);
+ ASSERT(!b->m_parent);
+
+ if (a == b)
+ return;
+
+ a->m_parent = b;
+ }
+private:
+ T* m_parent;
+};
+
+} // namespace WTF
+
+using WTF::UnionFind;
+
+#endif // UnionFind_h
diff --git a/Source/JavaScriptCore/wtf/UnusedParam.h b/Source/JavaScriptCore/wtf/UnusedParam.h
new file mode 100644
index 000000000..6ff6fd895
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/UnusedParam.h
@@ -0,0 +1,37 @@
+/*
+ * 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 WTF_UnusedParam_h
+#define WTF_UnusedParam_h
+
+/* 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. */
+
+#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/Source/JavaScriptCore/wtf/VMTags.h b/Source/JavaScriptCore/wtf/VMTags.h
new file mode 100644
index 000000000..117bc3721
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/VMTags.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 VMTags_h
+#define VMTags_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)
+
+#include <mach/vm_statistics.h>
+
+#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_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_JIT_REGISTER_FILE)
+
+#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)
+
+#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)
+
+#endif // VMTags_h
diff --git a/Source/JavaScriptCore/wtf/ValueCheck.h b/Source/JavaScriptCore/wtf/ValueCheck.h
new file mode 100644
index 000000000..2a86eb0f2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/ValueCheck.h
@@ -0,0 +1,53 @@
+/*
+ * 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 ValueCheck_h
+#define ValueCheck_h
+
+#include <wtf/FastMalloc.h>
+
+namespace WTF {
+
+template<typename T> struct ValueCheck {
+ typedef T TraitType;
+ static void checkConsistency(const T&) { }
+};
+
+#if !ASSERT_DISABLED
+template<typename P> struct ValueCheck<P*> {
+ typedef P* TraitType;
+ static void checkConsistency(const P* p)
+ {
+ if (!p)
+ return;
+ ASSERT(fastMallocSize(p));
+ ValueCheck<P>::checkConsistency(*p);
+ }
+};
+#endif
+
+}
+
+#endif // ValueCheck_h
diff --git a/Source/JavaScriptCore/wtf/Vector.h b/Source/JavaScriptCore/wtf/Vector.h
new file mode 100644
index 000000000..1368ac99b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/Vector.h
@@ -0,0 +1,1191 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WTF_Vector_h
+#define WTF_Vector_h
+
+#include "Alignment.h"
+#include "FastAllocBase.h"
+#include "Noncopyable.h"
+#include "NotFound.h"
+#include "StdLibExtras.h"
+#include "ValueCheck.h"
+#include "VectorTraits.h"
+#include <limits>
+#include <utility>
+
+#if PLATFORM(QT)
+#include <QDataStream>
+#endif
+
+namespace WTF {
+
+ using std::min;
+ using std::max;
+
+ template <bool needsDestruction, typename T>
+ struct VectorDestructor;
+
+ template<typename T>
+ struct VectorDestructor<false, T>
+ {
+ static void destruct(T*, T*) {}
+ };
+
+ template<typename T>
+ struct VectorDestructor<true, T>
+ {
+ static void destruct(T* begin, T* end)
+ {
+ for (T* cur = begin; cur != end; ++cur)
+ cur->~T();
+ }
+ };
+
+ template <bool needsInitialization, bool canInitializeWithMemset, typename T>
+ struct VectorInitializer;
+
+ template<bool ignore, typename T>
+ struct VectorInitializer<false, ignore, T>
+ {
+ static void initialize(T*, T*) {}
+ };
+
+ template<typename T>
+ struct VectorInitializer<true, false, T>
+ {
+ static void initialize(T* begin, T* end)
+ {
+ for (T* cur = begin; cur != end; ++cur)
+ new (NotNull, cur) T;
+ }
+ };
+
+ template<typename T>
+ struct VectorInitializer<true, true, T>
+ {
+ static void initialize(T* begin, T* end)
+ {
+ memset(begin, 0, reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin));
+ }
+ };
+
+ template <bool canMoveWithMemcpy, typename T>
+ struct VectorMover;
+
+ template<typename T>
+ struct VectorMover<false, T>
+ {
+ static void move(const T* src, const T* srcEnd, T* dst)
+ {
+ while (src != srcEnd) {
+ new (NotNull, dst) T(*src);
+#if COMPILER(SUNCC) && __SUNPRO_CC <= 0x590
+ const_cast<T*>(src)->~T(); // Work around obscure SunCC 12 compiler bug.
+#else
+ src->~T();
+#endif
+ ++dst;
+ ++src;
+ }
+ }
+ static void moveOverlapping(const T* src, const T* srcEnd, T* dst)
+ {
+ if (src > dst)
+ move(src, srcEnd, dst);
+ else {
+ T* dstEnd = dst + (srcEnd - src);
+ while (src != srcEnd) {
+ --srcEnd;
+ --dstEnd;
+ new (NotNull, dstEnd) T(*srcEnd);
+ srcEnd->~T();
+ }
+ }
+ }
+ };
+
+ template<typename T>
+ struct VectorMover<true, T>
+ {
+ static void move(const T* src, const T* srcEnd, T* dst)
+ {
+ memcpy(dst, src, reinterpret_cast<const char*>(srcEnd) - reinterpret_cast<const char*>(src));
+ }
+ static void moveOverlapping(const T* src, const T* srcEnd, T* dst)
+ {
+ memmove(dst, src, reinterpret_cast<const char*>(srcEnd) - reinterpret_cast<const char*>(src));
+ }
+ };
+
+ template <bool canCopyWithMemcpy, typename T>
+ struct VectorCopier;
+
+ template<typename T>
+ struct VectorCopier<false, T>
+ {
+ static void uninitializedCopy(const T* src, const T* srcEnd, T* dst)
+ {
+ while (src != srcEnd) {
+ new (NotNull, dst) T(*src);
+ ++dst;
+ ++src;
+ }
+ }
+ };
+
+ template<typename T>
+ struct VectorCopier<true, T>
+ {
+ static void uninitializedCopy(const T* src, const T* srcEnd, T* dst)
+ {
+ memcpy(dst, src, reinterpret_cast<const char*>(srcEnd) - reinterpret_cast<const char*>(src));
+ }
+ };
+
+ template <bool canFillWithMemset, typename T>
+ struct VectorFiller;
+
+ template<typename T>
+ struct VectorFiller<false, T>
+ {
+ static void uninitializedFill(T* dst, T* dstEnd, const T& val)
+ {
+ while (dst != dstEnd) {
+ new (NotNull, dst) T(val);
+ ++dst;
+ }
+ }
+ };
+
+ template<typename T>
+ struct VectorFiller<true, T>
+ {
+ static void uninitializedFill(T* dst, T* dstEnd, const T& val)
+ {
+ ASSERT(sizeof(T) == sizeof(char));
+ memset(dst, val, dstEnd - dst);
+ }
+ };
+
+ template<bool canCompareWithMemcmp, typename T>
+ struct VectorComparer;
+
+ template<typename T>
+ struct VectorComparer<false, T>
+ {
+ static bool compare(const T* a, const T* b, size_t size)
+ {
+ for (size_t i = 0; i < size; ++i)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+ };
+
+ template<typename T>
+ struct VectorComparer<true, T>
+ {
+ static bool compare(const T* a, const T* b, size_t size)
+ {
+ return memcmp(a, b, sizeof(T) * size) == 0;
+ }
+ };
+
+ template<typename T>
+ struct VectorTypeOperations
+ {
+ static void destruct(T* begin, T* end)
+ {
+ VectorDestructor<VectorTraits<T>::needsDestruction, T>::destruct(begin, end);
+ }
+
+ static void initialize(T* begin, T* end)
+ {
+ VectorInitializer<VectorTraits<T>::needsInitialization, VectorTraits<T>::canInitializeWithMemset, T>::initialize(begin, end);
+ }
+
+ static void move(const T* src, const T* srcEnd, T* dst)
+ {
+ VectorMover<VectorTraits<T>::canMoveWithMemcpy, T>::move(src, srcEnd, dst);
+ }
+
+ static void moveOverlapping(const T* src, const T* srcEnd, T* dst)
+ {
+ VectorMover<VectorTraits<T>::canMoveWithMemcpy, T>::moveOverlapping(src, srcEnd, dst);
+ }
+
+ static void uninitializedCopy(const T* src, const T* srcEnd, T* dst)
+ {
+ VectorCopier<VectorTraits<T>::canCopyWithMemcpy, T>::uninitializedCopy(src, srcEnd, dst);
+ }
+
+ static void uninitializedFill(T* dst, T* dstEnd, const T& val)
+ {
+ VectorFiller<VectorTraits<T>::canFillWithMemset, T>::uninitializedFill(dst, dstEnd, val);
+ }
+
+ static bool compare(const T* a, const T* b, size_t size)
+ {
+ return VectorComparer<VectorTraits<T>::canCompareWithMemcmp, T>::compare(a, b, size);
+ }
+ };
+
+ template<typename T>
+ class VectorBufferBase {
+ WTF_MAKE_NONCOPYABLE(VectorBufferBase);
+ public:
+ void allocateBuffer(size_t newCapacity)
+ {
+ ASSERT(newCapacity);
+ m_capacity = newCapacity;
+ if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T))
+ CRASH();
+ m_buffer = static_cast<T*>(fastMalloc(newCapacity * sizeof(T)));
+ }
+
+ bool tryAllocateBuffer(size_t newCapacity)
+ {
+ ASSERT(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) {
+ m_buffer = 0;
+ m_capacity = 0;
+ }
+ fastFree(bufferToDeallocate);
+ }
+
+ T* buffer() { return m_buffer; }
+ const T* buffer() const { return m_buffer; }
+ T** bufferSlot() { return &m_buffer; }
+ size_t capacity() const { return m_capacity; }
+
+ T* releaseBuffer()
+ {
+ T* buffer = m_buffer;
+ m_buffer = 0;
+ m_capacity = 0;
+ return buffer;
+ }
+
+ protected:
+ VectorBufferBase()
+ : m_buffer(0)
+ , m_capacity(0)
+ {
+ }
+
+ VectorBufferBase(T* buffer, size_t capacity)
+ : m_buffer(buffer)
+ , m_capacity(capacity)
+ {
+ }
+
+ ~VectorBufferBase()
+ {
+ // FIXME: It would be nice to find a way to ASSERT that m_buffer hasn't leaked here.
+ }
+
+ T* m_buffer;
+ size_t m_capacity;
+ };
+
+ template<typename T, size_t inlineCapacity>
+ class VectorBuffer;
+
+ template<typename T>
+ class VectorBuffer<T, 0> : private VectorBufferBase<T> {
+ private:
+ typedef VectorBufferBase<T> Base;
+ public:
+ VectorBuffer()
+ {
+ }
+
+ VectorBuffer(size_t capacity)
+ {
+ // Calling malloc(0) might take a lock and may actually do an
+ // allocation on some systems.
+ if (capacity)
+ allocateBuffer(capacity);
+ }
+
+ ~VectorBuffer()
+ {
+ deallocateBuffer(buffer());
+ }
+
+ void swap(VectorBuffer<T, 0>& other)
+ {
+ std::swap(m_buffer, other.m_buffer);
+ std::swap(m_capacity, other.m_capacity);
+ }
+
+ void restoreInlineBufferIfNeeded() { }
+
+ using Base::allocateBuffer;
+ using Base::tryAllocateBuffer;
+ using Base::deallocateBuffer;
+
+ using Base::buffer;
+ using Base::bufferSlot;
+ using Base::capacity;
+
+ using Base::releaseBuffer;
+ private:
+ using Base::m_buffer;
+ using Base::m_capacity;
+ };
+
+ template<typename T, size_t inlineCapacity>
+ class VectorBuffer : private VectorBufferBase<T> {
+ WTF_MAKE_NONCOPYABLE(VectorBuffer);
+ private:
+ typedef VectorBufferBase<T> Base;
+ public:
+ VectorBuffer()
+ : Base(inlineBuffer(), inlineCapacity)
+ {
+ }
+
+ VectorBuffer(size_t capacity)
+ : Base(inlineBuffer(), inlineCapacity)
+ {
+ if (capacity > inlineCapacity)
+ Base::allocateBuffer(capacity);
+ }
+
+ ~VectorBuffer()
+ {
+ deallocateBuffer(buffer());
+ }
+
+ void allocateBuffer(size_t newCapacity)
+ {
+ // FIXME: This should ASSERT(!m_buffer) to catch misuse/leaks.
+ if (newCapacity > inlineCapacity)
+ Base::allocateBuffer(newCapacity);
+ else {
+ m_buffer = inlineBuffer();
+ m_capacity = inlineCapacity;
+ }
+ }
+
+ 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())
+ return;
+ Base::deallocateBuffer(bufferToDeallocate);
+ }
+
+ void swap(VectorBuffer<T, inlineCapacity>& other)
+ {
+ if (buffer() == inlineBuffer() && other.buffer() == other.inlineBuffer()) {
+ WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
+ std::swap(m_capacity, other.m_capacity);
+ } else if (buffer() == inlineBuffer()) {
+ m_buffer = other.m_buffer;
+ other.m_buffer = other.inlineBuffer();
+ WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
+ std::swap(m_capacity, other.m_capacity);
+ } else if (other.buffer() == other.inlineBuffer()) {
+ other.m_buffer = m_buffer;
+ m_buffer = inlineBuffer();
+ WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
+ std::swap(m_capacity, other.m_capacity);
+ } else {
+ std::swap(m_buffer, other.m_buffer);
+ std::swap(m_capacity, other.m_capacity);
+ }
+ }
+
+ void restoreInlineBufferIfNeeded()
+ {
+ if (m_buffer)
+ return;
+ m_buffer = inlineBuffer();
+ m_capacity = inlineCapacity;
+ }
+
+ using Base::buffer;
+ using Base::bufferSlot;
+ using Base::capacity;
+
+ T* releaseBuffer()
+ {
+ if (buffer() == inlineBuffer())
+ return 0;
+ return Base::releaseBuffer();
+ }
+
+ private:
+ using Base::m_buffer;
+ using Base::m_capacity;
+
+ static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T);
+ T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); }
+
+ AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer;
+ };
+
+ template<typename T, size_t inlineCapacity = 0>
+ class Vector {
+ WTF_MAKE_FAST_ALLOCATED;
+ private:
+ typedef VectorBuffer<T, inlineCapacity> Buffer;
+ typedef VectorTypeOperations<T> TypeOperations;
+
+ class VectorReverseProxy;
+
+ public:
+ typedef T ValueType;
+
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ Vector()
+ : m_size(0)
+ {
+ }
+
+ explicit Vector(size_t size)
+ : m_size(size)
+ , m_buffer(size)
+ {
+ if (begin())
+ TypeOperations::initialize(begin(), end());
+ }
+
+ ~Vector()
+ {
+ if (m_size)
+ shrink(0);
+ }
+
+ Vector(const Vector&);
+ template<size_t otherCapacity>
+ Vector(const Vector<T, otherCapacity>&);
+
+ Vector& operator=(const Vector&);
+ template<size_t otherCapacity>
+ Vector& operator=(const Vector<T, otherCapacity>&);
+
+ size_t size() const { return m_size; }
+ size_t capacity() const { return m_buffer.capacity(); }
+ bool isEmpty() const { return !size(); }
+
+ T& at(size_t i)
+ {
+ ASSERT(i < size());
+ return m_buffer.buffer()[i];
+ }
+ const T& at(size_t i) const
+ {
+ ASSERT(i < size());
+ return m_buffer.buffer()[i];
+ }
+
+ T& operator[](size_t i) { return at(i); }
+ const T& operator[](size_t i) const { return at(i); }
+
+ T* data() { return m_buffer.buffer(); }
+ const T* data() const { return m_buffer.buffer(); }
+ T** dataSlot() { return m_buffer.bufferSlot(); }
+
+ iterator begin() { return data(); }
+ iterator end() { return begin() + m_size; }
+ const_iterator begin() const { return data(); }
+ const_iterator end() const { return begin() + m_size; }
+
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+
+ VectorReverseProxy& reversed() { return static_cast<VectorReverseProxy&>(*this); }
+ const VectorReverseProxy& reversed() const { return static_cast<const VectorReverseProxy&>(*this); }
+
+ T& first() { return at(0); }
+ const T& first() const { return at(0); }
+ T& last() { return at(size() - 1); }
+ const T& last() const { return at(size() - 1); }
+
+ template<typename U> bool contains(const U&) const;
+ 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()); }
+
+ void clear() { shrinkCapacity(0); }
+
+ template<typename U> void append(const U*, size_t);
+ 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&);
+ template<typename U, size_t c> void insert(size_t position, const Vector<U, c>&);
+
+ template<typename U> void prepend(const U*, size_t);
+ template<typename U> void prepend(const U&);
+ template<typename U, size_t c> void prepend(const Vector<U, c>&);
+
+ void remove(size_t position);
+ void remove(size_t position, size_t length);
+
+ void removeLast()
+ {
+ ASSERT(!isEmpty());
+ shrink(size() - 1);
+ }
+
+ Vector(size_t size, const T& val)
+ : m_size(size)
+ , m_buffer(size)
+ {
+ if (begin())
+ TypeOperations::uninitializedFill(begin(), end(), val);
+ }
+
+ void fill(const T&, size_t);
+ void fill(const T& val) { fill(val, size()); }
+
+ template<typename Iterator> void appendRange(Iterator start, Iterator end);
+
+ T* releaseBuffer();
+
+ void swap(Vector<T, inlineCapacity>& other)
+ {
+ std::swap(m_size, other.m_size);
+ m_buffer.swap(other.m_buffer);
+ }
+
+ void reverse();
+
+ void checkConsistency();
+
+ 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*);
+ template<typename U> void appendSlowCase(const U&);
+
+ class VectorReverseProxy : private Vector {
+ public:
+ typedef typename Vector::reverse_iterator iterator;
+ typedef typename Vector::const_reverse_iterator const_iterator;
+
+ iterator begin() { return Vector::rbegin(); }
+ iterator end() { return Vector::rend(); }
+ const_iterator begin() const { return Vector::rbegin(); }
+ const_iterator end() const { return Vector::rend(); }
+
+ private:
+ friend class Vector;
+
+ // These are intentionally not implemented.
+ VectorReverseProxy();
+ VectorReverseProxy(const VectorReverseProxy&);
+ VectorReverseProxy& operator=(const VectorReverseProxy&);
+ ~VectorReverseProxy();
+ };
+
+ size_t m_size;
+ Buffer m_buffer;
+ };
+
+#if PLATFORM(QT)
+ template<typename T>
+ QDataStream& operator<<(QDataStream& stream, const Vector<T>& data)
+ {
+ stream << qint64(data.size());
+ foreach (const T& i, data)
+ stream << i;
+ return stream;
+ }
+
+ template<typename T>
+ QDataStream& operator>>(QDataStream& stream, Vector<T>& data)
+ {
+ data.clear();
+ qint64 count;
+ T item;
+ stream >> count;
+ data.reserveCapacity(count);
+ for (qint64 i = 0; i < count; ++i) {
+ stream >> item;
+ data.append(item);
+ }
+ return stream;
+ }
+#endif
+
+ template<typename T, size_t inlineCapacity>
+ Vector<T, inlineCapacity>::Vector(const Vector& other)
+ : m_size(other.size())
+ , m_buffer(other.capacity())
+ {
+ if (begin())
+ TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
+ }
+
+ template<typename T, size_t inlineCapacity>
+ template<size_t otherCapacity>
+ Vector<T, inlineCapacity>::Vector(const Vector<T, otherCapacity>& other)
+ : m_size(other.size())
+ , m_buffer(other.capacity())
+ {
+ if (begin())
+ TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
+ }
+
+ template<typename T, size_t inlineCapacity>
+ Vector<T, inlineCapacity>& Vector<T, inlineCapacity>::operator=(const Vector<T, inlineCapacity>& other)
+ {
+ if (&other == this)
+ return *this;
+
+ if (size() > other.size())
+ shrink(other.size());
+ else if (other.size() > capacity()) {
+ clear();
+ reserveCapacity(other.size());
+ if (!begin())
+ 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();
+
+ 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 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()) {
+ clear();
+ reserveCapacity(other.size());
+ if (!begin())
+ 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();
+
+ return *this;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ template<typename U>
+ bool Vector<T, inlineCapacity>::contains(const U& value) const
+ {
+ return find(value) != notFound;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ template<typename U>
+ size_t Vector<T, inlineCapacity>::find(const U& value) const
+ {
+ for (size_t i = 0; i < size(); ++i) {
+ if (at(i) == value)
+ return i;
+ }
+ return notFound;
+ }
+
+ 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)
+ shrink(newSize);
+ else if (newSize > capacity()) {
+ clear();
+ reserveCapacity(newSize);
+ if (!begin())
+ return;
+ }
+
+ std::fill(begin(), end(), val);
+ TypeOperations::uninitializedFill(end(), begin() + newSize, val);
+ m_size = newSize;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ template<typename Iterator>
+ void Vector<T, inlineCapacity>::appendRange(Iterator start, Iterator end)
+ {
+ for (Iterator it = start; it != end; ++it)
+ append(*it);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::expandCapacity(size_t newMinCapacity)
+ {
+ reserveCapacity(max(newMinCapacity, max(static_cast<size_t>(16), capacity() + capacity() / 4 + 1)));
+ }
+
+ template<typename T, size_t inlineCapacity>
+ const T* Vector<T, inlineCapacity>::expandCapacity(size_t newMinCapacity, const T* ptr)
+ {
+ if (ptr < begin() || ptr >= end()) {
+ expandCapacity(newMinCapacity);
+ return ptr;
+ }
+ size_t index = ptr - begin();
+ expandCapacity(newMinCapacity);
+ 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)
+ {
+ expandCapacity(newMinCapacity);
+ return ptr;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::resize(size_t size)
+ {
+ if (size <= m_size)
+ TypeOperations::destruct(begin() + size, end());
+ else {
+ if (size > capacity())
+ expandCapacity(size);
+ if (begin())
+ TypeOperations::initialize(end(), begin() + size);
+ }
+
+ m_size = size;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::shrink(size_t size)
+ {
+ ASSERT(size <= m_size);
+ TypeOperations::destruct(begin() + size, end());
+ m_size = size;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::grow(size_t size)
+ {
+ ASSERT(size >= m_size);
+ if (size > capacity())
+ expandCapacity(size);
+ if (begin())
+ TypeOperations::initialize(end(), begin() + size);
+ m_size = size;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::reserveCapacity(size_t newCapacity)
+ {
+ if (newCapacity <= capacity())
+ return;
+ T* oldBuffer = begin();
+ T* oldEnd = end();
+ m_buffer.allocateBuffer(newCapacity);
+ if (begin())
+ TypeOperations::move(oldBuffer, oldEnd, begin());
+ m_buffer.deallocateBuffer(oldBuffer);
+ }
+
+ 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);
+ ASSERT(capacity() == inlineCapacity);
+ if (initialCapacity > inlineCapacity)
+ m_buffer.allocateBuffer(initialCapacity);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::shrinkCapacity(size_t newCapacity)
+ {
+ if (newCapacity >= capacity())
+ return;
+
+ if (newCapacity < size())
+ shrink(newCapacity);
+
+ T* oldBuffer = begin();
+ if (newCapacity > 0) {
+ T* oldEnd = end();
+ m_buffer.allocateBuffer(newCapacity);
+ if (begin() != oldBuffer)
+ TypeOperations::move(oldBuffer, oldEnd, begin());
+ }
+
+ m_buffer.deallocateBuffer(oldBuffer);
+ m_buffer.restoreInlineBufferIfNeeded();
+ }
+
+ // Templatizing these is better than just letting the conversion happen implicitly,
+ // because for instance it allows a PassRefPtr to be appended to a RefPtr vector
+ // without refcount thrash.
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ void Vector<T, inlineCapacity>::append(const U* data, size_t dataSize)
+ {
+ size_t newSize = m_size + dataSize;
+ if (newSize > capacity()) {
+ data = expandCapacity(newSize, data);
+ if (!begin())
+ return;
+ }
+ if (newSize < m_size)
+ CRASH();
+ T* dest = end();
+ for (size_t i = 0; i < dataSize; ++i)
+ new (NotNull, &dest[i]) T(data[i]);
+ m_size = newSize;
+ }
+
+ 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 (NotNull, &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)
+ {
+ if (size() != capacity()) {
+ new (NotNull, end()) T(val);
+ ++m_size;
+ return;
+ }
+
+ appendSlowCase(val);
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ void Vector<T, inlineCapacity>::appendSlowCase(const U& val)
+ {
+ ASSERT(size() == capacity());
+
+ const U* ptr = &val;
+ ptr = expandCapacity(size() + 1, ptr);
+ if (!begin())
+ return;
+
+ new (NotNull, end()) T(*ptr);
+ ++m_size;
+ }
+
+ // This version of append saves a branch in the case where you know that the
+ // vector's capacity is large enough for the append to succeed.
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Vector<T, inlineCapacity>::uncheckedAppend(const U& val)
+ {
+ ASSERT(size() < capacity());
+ const U* ptr = &val;
+ new (NotNull, end()) T(*ptr);
+ ++m_size;
+ }
+
+ // This method should not be called append, a better name would be appendElements.
+ // It could also be eliminated entirely, and call sites could just use
+ // appendRange(val.begin(), val.end()).
+ template<typename T, size_t inlineCapacity> template<size_t otherCapacity>
+ inline void Vector<T, inlineCapacity>::append(const Vector<T, otherCapacity>& val)
+ {
+ append(val.begin(), val.size());
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ void Vector<T, inlineCapacity>::insert(size_t position, const U* data, size_t dataSize)
+ {
+ ASSERT(position <= size());
+ size_t newSize = m_size + dataSize;
+ if (newSize > capacity()) {
+ data = expandCapacity(newSize, data);
+ if (!begin())
+ return;
+ }
+ if (newSize < m_size)
+ CRASH();
+ T* spot = begin() + position;
+ TypeOperations::moveOverlapping(spot, end(), spot + dataSize);
+ for (size_t i = 0; i < dataSize; ++i)
+ new (NotNull, &spot[i]) T(data[i]);
+ m_size = newSize;
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Vector<T, inlineCapacity>::insert(size_t position, const U& val)
+ {
+ ASSERT(position <= size());
+ const U* data = &val;
+ if (size() == capacity()) {
+ data = expandCapacity(size() + 1, data);
+ if (!begin())
+ return;
+ }
+ T* spot = begin() + position;
+ TypeOperations::moveOverlapping(spot, end(), spot + 1);
+ new (NotNull, spot) T(*data);
+ ++m_size;
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U, size_t c>
+ inline void Vector<T, inlineCapacity>::insert(size_t position, const Vector<U, c>& val)
+ {
+ insert(position, val.begin(), val.size());
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ void Vector<T, inlineCapacity>::prepend(const U* data, size_t dataSize)
+ {
+ insert(0, data, dataSize);
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Vector<T, inlineCapacity>::prepend(const U& val)
+ {
+ insert(0, val);
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U, size_t c>
+ inline void Vector<T, inlineCapacity>::prepend(const Vector<U, c>& val)
+ {
+ insert(0, val.begin(), val.size());
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::remove(size_t position)
+ {
+ ASSERT(position < size());
+ T* spot = begin() + position;
+ spot->~T();
+ TypeOperations::moveOverlapping(spot + 1, end(), spot);
+ --m_size;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::remove(size_t position, size_t length)
+ {
+ ASSERT(position < size());
+ ASSERT(position + length <= size());
+ T* beginSpot = begin() + position;
+ T* endSpot = beginSpot + length;
+ TypeOperations::destruct(beginSpot, endSpot);
+ TypeOperations::moveOverlapping(endSpot, end(), beginSpot);
+ m_size -= length;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::reverse()
+ {
+ for (size_t i = 0; i < m_size / 2; ++i)
+ std::swap(at(i), at(m_size - 1 - i));
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline T* Vector<T, inlineCapacity>::releaseBuffer()
+ {
+ T* buffer = m_buffer.releaseBuffer();
+ if (inlineCapacity && !buffer && m_size) {
+ // If the vector had some data, but no buffer to release,
+ // that means it was using the inline buffer. In that case,
+ // we create a brand new buffer so the caller always gets one.
+ size_t bytes = m_size * sizeof(T);
+ buffer = static_cast<T*>(fastMalloc(bytes));
+ memcpy(buffer, data(), bytes);
+ }
+ m_size = 0;
+ return buffer;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::checkConsistency()
+ {
+#if !ASSERT_DISABLED
+ for (size_t i = 0; i < size(); ++i)
+ ValueCheck<T>::checkConsistency(at(i));
+#endif
+ }
+
+ template<typename T, size_t inlineCapacity>
+ void deleteAllValues(const Vector<T, inlineCapacity>& collection)
+ {
+ typedef typename Vector<T, inlineCapacity>::const_iterator iterator;
+ iterator end = collection.end();
+ for (iterator it = collection.begin(); it != end; ++it)
+ delete *it;
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline void swap(Vector<T, inlineCapacity>& a, Vector<T, inlineCapacity>& b)
+ {
+ a.swap(b);
+ }
+
+ template<typename T, size_t inlineCapacity>
+ bool operator==(const Vector<T, inlineCapacity>& a, const Vector<T, inlineCapacity>& b)
+ {
+ if (a.size() != b.size())
+ return false;
+
+ return VectorTypeOperations<T>::compare(a.data(), b.data(), a.size());
+ }
+
+ template<typename T, size_t inlineCapacity>
+ inline bool operator!=(const Vector<T, inlineCapacity>& a, const Vector<T, inlineCapacity>& b)
+ {
+ return !(a == b);
+ }
+
+#if !ASSERT_DISABLED
+ template<typename T> struct ValueCheck<Vector<T> > {
+ typedef Vector<T> TraitType;
+ static void checkConsistency(const Vector<T>& v)
+ {
+ v.checkConsistency();
+ }
+ };
+#endif
+
+} // namespace WTF
+
+using WTF::Vector;
+
+#endif // WTF_Vector_h
diff --git a/Source/JavaScriptCore/wtf/VectorTraits.h b/Source/JavaScriptCore/wtf/VectorTraits.h
new file mode 100644
index 000000000..6777c9ebf
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/VectorTraits.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WTF_VectorTraits_h
+#define WTF_VectorTraits_h
+
+#include "OwnPtr.h"
+#include "RefPtr.h"
+#include "TypeTraits.h"
+#include <utility>
+#include <memory>
+
+using std::pair;
+
+namespace WTF {
+
+ template<bool isPod, typename T>
+ struct VectorTraitsBase;
+
+ template<typename T>
+ struct VectorTraitsBase<false, T>
+ {
+ static const bool needsDestruction = true;
+ static const bool needsInitialization = true;
+ static const bool canInitializeWithMemset = false;
+ static const bool canMoveWithMemcpy = false;
+ static const bool canCopyWithMemcpy = false;
+ static const bool canFillWithMemset = false;
+ static const bool canCompareWithMemcmp = false;
+ };
+
+ template<typename T>
+ struct VectorTraitsBase<true, T>
+ {
+ static const bool needsDestruction = false;
+ static const bool needsInitialization = false;
+ static const bool canInitializeWithMemset = false;
+ static const bool canMoveWithMemcpy = true;
+ static const bool canCopyWithMemcpy = true;
+ static const bool canFillWithMemset = sizeof(T) == sizeof(char);
+ static const bool canCompareWithMemcmp = true;
+ };
+
+ template<typename T>
+ struct VectorTraits : VectorTraitsBase<IsPod<T>::value, T> { };
+
+ struct SimpleClassVectorTraits : VectorTraitsBase<false, void>
+ {
+ static const bool canInitializeWithMemset = true;
+ static const bool canMoveWithMemcpy = true;
+ static const bool canCompareWithMemcmp = true;
+ };
+
+ // we know OwnPtr and RefPtr are simple enough that initializing to 0 and moving with memcpy
+ // (and then not destructing the original) will totally work
+ template<typename P>
+ struct VectorTraits<RefPtr<P> > : SimpleClassVectorTraits { };
+
+ template<typename P>
+ struct VectorTraits<OwnPtr<P> > : SimpleClassVectorTraits { };
+
+ template<typename First, typename Second>
+ struct VectorTraits<pair<First, Second> >
+ {
+ typedef VectorTraits<First> FirstTraits;
+ typedef VectorTraits<Second> SecondTraits;
+
+ static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
+ static const bool needsInitialization = FirstTraits::needsInitialization || SecondTraits::needsInitialization;
+ static const bool canInitializeWithMemset = FirstTraits::canInitializeWithMemset && SecondTraits::canInitializeWithMemset;
+ static const bool canMoveWithMemcpy = FirstTraits::canMoveWithMemcpy && SecondTraits::canMoveWithMemcpy;
+ static const bool canCopyWithMemcpy = FirstTraits::canCopyWithMemcpy && SecondTraits::canCopyWithMemcpy;
+ static const bool canFillWithMemset = false;
+ static const bool canCompareWithMemcmp = FirstTraits::canCompareWithMemcmp && SecondTraits::canCompareWithMemcmp;
+ };
+
+} // namespace WTF
+
+using WTF::VectorTraits;
+using WTF::SimpleClassVectorTraits;
+
+#endif // WTF_VectorTraits_h
diff --git a/Source/JavaScriptCore/wtf/WTFThreadData.cpp b/Source/JavaScriptCore/wtf/WTFThreadData.cpp
new file mode 100644
index 000000000..241fbe449
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/WTFThreadData.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 {
+
+ThreadSpecific<WTFThreadData>* WTFThreadData::staticData;
+
+WTFThreadData::WTFThreadData()
+ : m_atomicStringTable(0)
+ , m_atomicStringTableDestructor(0)
+#if USE(JSC)
+ , m_defaultIdentifierTable(new JSC::IdentifierTable())
+ , m_currentIdentifierTable(m_defaultIdentifierTable)
+ , m_stackBounds(StackBounds::currentThreadStackBounds())
+#endif
+{
+}
+
+WTFThreadData::~WTFThreadData()
+{
+ if (m_atomicStringTableDestructor)
+ m_atomicStringTableDestructor(m_atomicStringTable);
+#if USE(JSC)
+ delete m_defaultIdentifierTable;
+#endif
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/WTFThreadData.h b/Source/JavaScriptCore/wtf/WTFThreadData.h
new file mode 100644
index 000000000..81b817f6f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/WTFThreadData.h
@@ -0,0 +1,146 @@
+/*
+ * 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/StackBounds.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/ThreadSpecific.h>
+#include <wtf/Threading.h>
+
+#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 {
+ WTF_MAKE_FAST_ALLOCATED;
+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 {
+ WTF_MAKE_NONCOPYABLE(WTFThreadData);
+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;
+ }
+
+ const StackBounds& stack() const
+ {
+ return m_stackBounds;
+ }
+#endif
+
+private:
+ AtomicStringTable* m_atomicStringTable;
+ AtomicStringTableDestructor m_atomicStringTableDestructor;
+
+#if USE(JSC)
+ JSC::IdentifierTable* m_defaultIdentifierTable;
+ JSC::IdentifierTable* m_currentIdentifierTable;
+ StackBounds m_stackBounds;
+#endif
+
+ static WTF_EXPORTDATA ThreadSpecific<WTFThreadData>* staticData;
+ friend WTFThreadData& wtfThreadData();
+ friend class AtomicStringTable;
+};
+
+inline WTFThreadData& wtfThreadData()
+{
+ // 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;
+}
+
+} // namespace WTF
+
+using WTF::WTFThreadData;
+using WTF::wtfThreadData;
+
+#endif // WTFThreadData_h
diff --git a/Source/JavaScriptCore/wtf/blackberry/MainThreadBlackBerry.cpp b/Source/JavaScriptCore/wtf/blackberry/MainThreadBlackBerry.cpp
new file mode 100644
index 000000000..7284f4b44
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/blackberry/MainThreadBlackBerry.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009, 2010, 2011 Research In Motion Limited. 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
+ */
+
+#include "config.h"
+#include "MainThread.h"
+
+#include <BlackBerryPlatformClient.h>
+
+namespace WTF {
+
+void initializeMainThreadPlatform()
+{
+}
+
+void scheduleDispatchFunctionsOnMainThread()
+{
+ BlackBerry::Platform::Client::get()->scheduleCallOnMainThread(dispatchFunctionsFromMainThread);
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/chromium/ChromiumThreading.h b/Source/JavaScriptCore/wtf/chromium/ChromiumThreading.h
new file mode 100644
index 000000000..39386219d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/chromium/ChromiumThreading.h
@@ -0,0 +1,44 @@
+/*
+* Copyright (C) 2009 Google Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following disclaimer
+* in the documentation and/or other materials provided with the
+* distribution.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ChromiumThreading_h
+#define ChromiumThreading_h
+
+namespace WTF {
+
+// An interface to the embedding layer, which provides threading support.
+class ChromiumThreading {
+public:
+ static void callOnMainThread(void (*func)(void*), void* context);
+};
+
+} // namespace WTF
+
+#endif // ChromiumThreading_h
diff --git a/Source/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp b/Source/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp
new file mode 100644
index 000000000..9e6592b57
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp
@@ -0,0 +1,73 @@
+/*
+* Copyright (C) 2009 Google Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following disclaimer
+* in the documentation and/or other materials provided with the
+* distribution.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "MainThread.h"
+
+#include "Assertions.h"
+#include "ChromiumThreading.h"
+#include "Threading.h"
+
+namespace WTF {
+
+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)
+{
+ ASSERT_NOT_REACHED();
+}
+
+bool isMainThread()
+{
+ return currentThread() == mainThreadIdentifier;
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/wtf/dtoa.cpp b/Source/JavaScriptCore/wtf/dtoa.cpp
new file mode 100644
index 000000000..3732fe614
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa.cpp
@@ -0,0 +1,1867 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ * 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
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* 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
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 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
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+#include "config.h"
+#include "dtoa.h"
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#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/FastMalloc.h>
+#include <wtf/MathExtras.h>
+#include <wtf/Threading.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+#include <wtf/dtoa/double-conversion.h>
+
+#if COMPILER(MSVC)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4245)
+#pragma warning(disable: 4554)
+#endif
+
+namespace WTF {
+
+Mutex* s_dtoaP5Mutex;
+
+typedef union {
+ double d;
+ uint32_t L[2];
+} U;
+
+#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#else
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * *p++ = high << 16 | low & 0xffff;
+ */
+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
+ p16[1] = high;
+ p16[0] = low;
+#endif
+ return p + 1;
+}
+
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#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
+
+#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
+
+struct BigInt {
+ BigInt() : sign(0) { }
+ int sign;
+
+ void clear()
+ {
+ sign = 0;
+ m_words.clear();
+ }
+
+ size_t size() const
+ {
+ return m_words.size();
+ }
+
+ void resize(size_t s)
+ {
+ m_words.resize(s);
+ }
+
+ uint32_t* words()
+ {
+ return m_words.data();
+ }
+
+ const uint32_t* words() const
+ {
+ return m_words.data();
+ }
+
+ void append(uint32_t w)
+ {
+ m_words.append(w);
+ }
+
+ Vector<uint32_t, 16> m_words;
+};
+
+static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */
+{
+#ifdef USE_LONG_LONG
+ unsigned long long carry;
+#else
+ uint32_t carry;
+#endif
+
+ int wds = b.size();
+ uint32_t* x = b.words();
+ int i = 0;
+ carry = a;
+ do {
+#ifdef USE_LONG_LONG
+ unsigned long long y = *x * (unsigned long long)m + carry;
+ carry = y >> 32;
+ *x++ = (uint32_t)y & 0xffffffffUL;
+#else
+ 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);
+#endif
+ } while (++i < wds);
+
+ if (carry)
+ b.append((uint32_t)carry);
+}
+
+static void s2b(BigInt& b, const char* s, int nd0, int nd, uint32_t y9)
+{
+ b.sign = 0;
+ b.resize(1);
+ b.words()[0] = y9;
+
+ int i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do {
+ multadd(b, 10, *s++ - '0');
+ } while (++i < nd0);
+ s++;
+ } else
+ s += 10;
+ for (; i < nd; i++)
+ multadd(b, 10, *s++ - '0');
+}
+
+static int hi0bits(uint32_t x)
+{
+ int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+static int lo0bits(uint32_t* y)
+{
+ int k;
+ uint32_t x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+static void i2b(BigInt& b, int i)
+{
+ b.sign = 0;
+ b.resize(1);
+ b.words()[0] = i;
+}
+
+static void mult(BigInt& aRef, const BigInt& bRef)
+{
+ const BigInt* a = &aRef;
+ const BigInt* b = &bRef;
+ BigInt c;
+ int wa, wb, wc;
+ 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;
+#else
+ uint32_t carry, z;
+#endif
+
+ if (a->size() < b->size()) {
+ const BigInt* tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ wa = a->size();
+ wb = b->size();
+ wc = wa + wb;
+ c.resize(wc);
+
+ for (xc = c.words(), xa = xc + wc; xc < xa; xc++)
+ *xc = 0;
+ xa = a->words();
+ xae = xa + wa;
+ xb = b->words();
+ xbe = xb + wb;
+ xc0 = c.words();
+#ifdef USE_LONG_LONG
+ for (; xb < xbe; xc0++) {
+ if ((y = *xb++)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (unsigned long long)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (uint32_t)z & 0xffffffffUL;
+ } while (x < xae);
+ *xc = (uint32_t)carry;
+ }
+ }
+#else
+ for (; xb < xbe; xb++, xc0++) {
+ if ((y = *xb & 0xffff)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ xc = storeInc(xc, z2, z);
+ } while (x < xae);
+ *xc = carry;
+ }
+ if ((y = *xb >> 16)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ uint32_t z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ xc = storeInc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while (x < xae);
+ *xc = z2;
+ }
+ }
+#endif
+ for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { }
+ c.resize(wc);
+ aRef = c;
+}
+
+struct P5Node {
+ WTF_MAKE_NONCOPYABLE(P5Node); WTF_MAKE_FAST_ALLOCATED;
+public:
+ P5Node() { }
+ BigInt val;
+ P5Node* next;
+};
+
+static P5Node* p5s;
+static int p5sCount;
+
+static ALWAYS_INLINE void pow5mult(BigInt& b, int k)
+{
+ static int p05[3] = { 5, 25, 125 };
+
+ if (int i = k & 3)
+ multadd(b, p05[i - 1], 0);
+
+ if (!(k >>= 2))
+ return;
+
+ s_dtoaP5Mutex->lock();
+ P5Node* p5 = p5s;
+
+ if (!p5) {
+ /* first time */
+ p5 = new P5Node;
+ i2b(p5->val, 625);
+ p5->next = 0;
+ p5s = p5;
+ p5sCount = 1;
+ }
+
+ int p5sCountLocal = p5sCount;
+ s_dtoaP5Mutex->unlock();
+ int p5sUsed = 0;
+
+ for (;;) {
+ if (k & 1)
+ mult(b, p5->val);
+
+ if (!(k >>= 1))
+ break;
+
+ if (++p5sUsed == p5sCountLocal) {
+ s_dtoaP5Mutex->lock();
+ 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);
+ ++p5sCount;
+ }
+
+ p5sCountLocal = p5sCount;
+ s_dtoaP5Mutex->unlock();
+ }
+ p5 = p5->next;
+ }
+}
+
+static ALWAYS_INLINE void lshift(BigInt& b, int k)
+{
+ int n = k >> 5;
+
+ int origSize = b.size();
+ int n1 = n + origSize + 1;
+
+ if (k &= 0x1f)
+ b.resize(b.size() + n + 1);
+ else
+ b.resize(b.size() + n);
+
+ const uint32_t* srcStart = b.words();
+ uint32_t* dstStart = b.words();
+ const uint32_t* src = srcStart + origSize - 1;
+ uint32_t* dst = dstStart + n1 - 1;
+ if (k) {
+ uint32_t hiSubword = 0;
+ int s = 32 - k;
+ for (; src >= srcStart; --src) {
+ *dst-- = hiSubword | *src >> s;
+ hiSubword = *src << k;
+ }
+ *dst = hiSubword;
+ ASSERT(dst == dstStart + n);
+
+ b.resize(origSize + n + !!b.words()[n1 - 1]);
+ }
+ else {
+ do {
+ *--dst = *src--;
+ } while (src >= srcStart);
+ }
+ for (dst = dstStart + n; dst != dstStart; )
+ *--dst = 0;
+
+ ASSERT(b.size() <= 1 || b.words()[b.size() - 1]);
+}
+
+static int cmp(const BigInt& a, const BigInt& b)
+{
+ const uint32_t *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a.size();
+ j = b.size();
+ ASSERT(i <= 1 || a.words()[i - 1]);
+ ASSERT(j <= 1 || b.words()[j - 1]);
+ if (i -= j)
+ return i;
+ xa0 = a.words();
+ xa = xa0 + j;
+ xb0 = b.words();
+ xb = xb0 + j;
+ for (;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+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;
+
+ i = cmp(*a, *b);
+ if (!i) {
+ c.sign = 0;
+ c.resize(1);
+ c.words()[0] = 0;
+ return;
+ }
+ if (i < 0) {
+ const BigInt* tmp = a;
+ a = b;
+ b = tmp;
+ i = 1;
+ } else
+ i = 0;
+
+ wa = a->size();
+ const uint32_t* xa = a->words();
+ const uint32_t* xae = xa + wa;
+ wb = b->size();
+ const uint32_t* xb = b->words();
+ const uint32_t* xbe = xb + wb;
+
+ c.resize(wa);
+ c.sign = i;
+ xc = c.words();
+#ifdef USE_LONG_LONG
+ unsigned long long borrow = 0;
+ do {
+ unsigned long long y = (unsigned long long)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *xc++ = (uint32_t)y & 0xffffffffUL;
+ } while (xb < xbe);
+ while (xa < xae) {
+ unsigned long long y = *xa++ - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *xc++ = (uint32_t)y & 0xffffffffUL;
+ }
+#else
+ uint32_t borrow = 0;
+ 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;
+ 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;
+ xc = storeInc(xc, z, y);
+ }
+#endif
+ while (!*--xc)
+ wa--;
+ c.resize(wa);
+}
+
+static double ulp(U *x)
+{
+ register int32_t L;
+ U u;
+
+ L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
+ word0(&u) = L;
+ word1(&u) = 0;
+ return dval(&u);
+}
+
+static double b2d(const BigInt& a, int* e)
+{
+ const uint32_t* xa;
+ const uint32_t* xa0;
+ uint32_t w;
+ uint32_t y;
+ uint32_t z;
+ int k;
+ U d;
+
+#define d0 word0(&d)
+#define d1 word1(&d)
+
+ xa0 = a.words();
+ xa = xa0 + a.size();
+ y = *--xa;
+ ASSERT(y);
+ k = hi0bits(y);
+ *e = 32 - k;
+ if (k < Ebits) {
+ d0 = Exp_1 | (y >> (Ebits - k));
+ w = xa > xa0 ? *--xa : 0;
+ d1 = (y << (32 - Ebits + k)) | (w >> (Ebits - k));
+ goto returnD;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | (y << k) | (z >> (32 - k));
+ y = xa > xa0 ? *--xa : 0;
+ d1 = (z << k) | (y >> (32 - k));
+ } else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+returnD:
+#undef d0
+#undef d1
+ return dval(&d);
+}
+
+static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits)
+{
+ int de, k;
+ uint32_t* x;
+ uint32_t y, z;
+ int i;
+#define d0 word0(d)
+#define d1 word1(d)
+
+ b.sign = 0;
+ b.resize(1);
+ x = b.words();
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+ if ((de = (int)(d0 >> Exp_shift)))
+ z |= Exp_msk1;
+ 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;
+ }
+
+ i = b.size();
+ } else {
+ k = lo0bits(&z);
+ x[0] = z;
+ i = 1;
+ b.resize(1);
+ k += 32;
+ }
+ if (de) {
+ *e = de - Bias - (P - 1) + k;
+ *bits = P - k;
+ } else {
+ *e = 0 - Bias - (P - 1) + 1 + k;
+ *bits = (32 * i) - hi0bits(x[i - 1]);
+ }
+}
+#undef d0
+#undef d1
+
+static double ratio(const BigInt& a, const BigInt& b)
+{
+ U da, db;
+ int k, ka, kb;
+
+ dval(&da) = b2d(a, &ka);
+ dval(&db) = b2d(b, &kb);
+ k = ka - kb + 32 * (a.size() - b.size());
+ if (k > 0)
+ word0(&da) += k * Exp_msk1;
+ else {
+ k = -k;
+ word0(&db) += k * Exp_msk1;
+ }
+ return dval(&da) / dval(&db);
+}
+
+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
+};
+
+static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+ 9007199254740992. * 9007199254740992.e-256
+ /* = 2^106 * 1e-256 */
+};
+
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+
+double strtod(const char* s00, char** se)
+{
+ int scale;
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ 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;
+
+ sign = nz0 = nz = 0;
+ dval(&rv) = 0;
+ 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:
+ goto break2;
+ }
+ }
+break2:
+ if (*s == '0') {
+ nz0 = 1;
+ while (*++s == '0') { }
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = (10 * y) + c - '0';
+ else if (nd < 16)
+ z = (10 * z) + c - '0';
+ nd0 = nd;
+ if (c == '.') {
+ c = *++s;
+ if (!nd) {
+ for (; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto haveDig;
+ }
+ goto digDone;
+ }
+ for (; c >= '0' && c <= '9'; c = *++s) {
+haveDig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for (i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = (10 * y) + c;
+ else if (nd <= DBL_DIG + 1)
+ z = (10 * z) + c;
+ nz = 0;
+ }
+ }
+ }
+digDone:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0)
+ goto ret0;
+ s00 = s;
+ esign = 0;
+ switch (c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while (c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while ((c = *++s) >= '0' && c <= '9')
+ L = (10 * L) + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ } else
+ e = 0;
+ } else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+ret0:
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ dval(&rv) = y;
+ if (k > 9)
+ dval(&rv) = tens[k - 9] * dval(&rv) + z;
+ if (nd <= DBL_DIG) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+ goto ret;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ dval(&rv) *= tens[i];
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+ goto ret;
+ }
+ } else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+ goto ret;
+ }
+ }
+ e1 += nd - k;
+
+ scale = 0;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15))
+ dval(&rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+#if HAVE(ERRNO_H)
+ errno = ERANGE;
+#endif
+ /* Can't trust HUGE_VAL */
+ word0(&rv) = Exp_mask;
+ word1(&rv) = 0;
+ goto ret;
+ }
+ e1 >>= 4;
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(&rv) -= P * Exp_msk1;
+ dval(&rv) *= bigtens[j];
+ if ((z = word0(&rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P))
+ goto ovfl;
+ if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ } else
+ word0(&rv) += P * Exp_msk1;
+ }
+ } else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15))
+ dval(&rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+ 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; clear j low bits */
+ if (j >= 32) {
+ word1(&rv) = 0;
+ if (j >= 53)
+ word0(&rv) = (P + 2) * Exp_msk1;
+ else
+ word0(&rv) &= 0xffffffff << (j - 32);
+ } else
+ word1(&rv) &= 0xffffffff << j;
+ }
+ if (!dval(&rv)) {
+undfl:
+ dval(&rv) = 0.;
+#if HAVE(ERRNO_H)
+ errno = ERANGE;
+#endif
+ goto ret;
+ }
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ s2b(bd0, s0, nd0, nd, y);
+
+ for (;;) {
+ bd = bd0;
+ d2b(bb, &rv, &bbe, &bbbits); /* rv = bb * 2^bbe */
+ i2b(bs, 1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ } else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+ j = bbe - scale;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+ bb2 += j;
+ bd2 += j;
+ bd2 += scale;
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ pow5mult(bs, bb5);
+ mult(bb, bs);
+ }
+ if (bb2 > 0)
+ lshift(bb, bb2);
+ if (bd5 > 0)
+ pow5mult(bd, bd5);
+ if (bd2 > 0)
+ lshift(bd, bd2);
+ if (bs2 > 0)
+ lshift(bs, bs2);
+ diff(delta, bb, bd);
+ dsign = delta.sign;
+ delta.sign = 0;
+ i = cmp(delta, bs);
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask
+ || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1
+ ) {
+ break;
+ }
+ if (!delta.words()[0] && delta.size() <= 1) {
+ /* exact result */
+ break;
+ }
+ lshift(delta, Log2P);
+ if (cmp(delta, bs) > 0)
+ goto dropDown;
+ break;
+ }
+ if (!i) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+ && word1(&rv) == (
+ (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
+ ? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) :
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1;
+ word1(&rv) = 0;
+ dsign = 0;
+ break;
+ }
+ } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+dropDown:
+ /* boundary case -- decrement exponent */
+ if (scale) {
+ L = word0(&rv) & Exp_mask;
+ if (L <= (2 * P + 1) * Exp_msk1) {
+ if (L > (P + 2) * Exp_msk1)
+ /* round even ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest denormal */
+ goto undfl;
+ }
+ }
+ L = (word0(&rv) & Exp_mask) - Exp_msk1;
+ word0(&rv) = L | Bndry_mask1;
+ word1(&rv) = 0xffffffff;
+ break;
+ }
+ if (!(word1(&rv) & LSB))
+ break;
+ if (dsign)
+ dval(&rv) += ulp(&rv);
+ else {
+ dval(&rv) -= ulp(&rv);
+ if (!dval(&rv))
+ goto undfl;
+ }
+ dsign = 1 - dsign;
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+ if (word1(&rv) == Tiny1 && !word0(&rv))
+ goto undfl;
+ aadj = 1.;
+ aadj1 = -1.;
+ } else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2. / FLT_RADIX)
+ aadj = 1. / FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ } else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+ }
+ y = word0(&rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) {
+ dval(&rv0) = dval(&rv);
+ word0(&rv) -= P * Exp_msk1;
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ if ((word0(&rv) & Exp_mask) >= Exp_msk1 * (DBL_MAX_EXP + Bias - P)) {
+ if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
+ goto ovfl;
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ goto cont;
+ }
+ word0(&rv) += P * Exp_msk1;
+ } else {
+ if (scale && y <= 2 * P * Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (uint32_t)aadj) <= 0)
+ z = 1;
+ aadj = z;
+ aadj1 = dsign ? aadj : -aadj;
+ }
+ dval(&aadj2) = aadj1;
+ word0(&aadj2) += (2 * P + 1) * Exp_msk1 - y;
+ aadj1 = dval(&aadj2);
+ }
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ }
+ z = word0(&rv) & Exp_mask;
+ if (!scale && y == z) {
+ /* Can we stop now? */
+ L = (int32_t)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ } else if (aadj < .4999999 / FLT_RADIX)
+ break;
+ }
+cont:
+ {}
+ }
+ if (scale) {
+ word0(&rv0) = Exp_1 - 2 * P * Exp_msk1;
+ word1(&rv0) = 0;
+ dval(&rv) *= dval(&rv0);
+#if HAVE(ERRNO_H)
+ /* try to avoid the bug of testing an 8087 register value */
+ if (!word0(&rv) && !word1(&rv))
+ errno = ERANGE;
+#endif
+ }
+ret:
+ if (se)
+ *se = const_cast<char*>(s);
+ return sign ? -dval(&rv) : dval(&rv);
+}
+
+static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S)
+{
+ size_t n;
+ 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;
+ uint32_t si, z, zs;
+#endif
+ ASSERT(b.size() <= 1 || b.words()[b.size() - 1]);
+ ASSERT(S.size() <= 1 || S.words()[S.size() - 1]);
+
+ n = S.size();
+ ASSERT_WITH_MESSAGE(b.size() <= n, "oversize b in quorem");
+ if (b.size() < n)
+ return 0;
+ sx = S.words();
+ sxe = sx + --n;
+ bx = b.words();
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+ ASSERT_WITH_MESSAGE(q <= 9, "oversized quotient in quorem");
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef USE_LONG_LONG
+ ys = *sx++ * (unsigned long long)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *bx++ = (uint32_t)y & 0xffffffffUL;
+#else
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ bx = storeInc(bx, z, y);
+#endif
+ } while (sx <= sxe);
+ if (!*bxe) {
+ bx = b.words();
+ while (--bxe > bx && !*bxe)
+ --n;
+ b.resize(n);
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b.words();
+ sx = S.words();
+ do {
+#ifdef USE_LONG_LONG
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *bx++ = (uint32_t)y & 0xffffffffUL;
+#else
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ bx = storeInc(bx, z, y);
+#endif
+ } while (sx <= sxe);
+ bx = b.words();
+ bxe = bx + n;
+ if (!*bxe) {
+ while (--bxe > bx && !*bxe)
+ --n;
+ b.resize(n);
+ }
+ }
+ return q;
+}
+
+/* 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. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "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'.
+ */
+template<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright>
+void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut)
+{
+ // Exactly one rounding mode must be specified.
+ ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1);
+ // roundingNone only allowed (only sensible?) with leftright set.
+ ASSERT(!roundingNone || leftright);
+
+ ASSERT(isfinite(dd));
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0,
+ j, j1, k, k0, k_check, m2, m5, s2, s5,
+ spec_case;
+ int32_t L;
+ int denorm;
+ uint32_t x;
+ BigInt b, delta, mlo, mhi, S;
+ U d2, eps, u;
+ double ds;
+ char* s;
+ char* s0;
+
+ u.d = dd;
+
+ /* Infinity or NaN */
+ ASSERT((word0(&u) & Exp_mask) != Exp_mask);
+
+ // JavaScript toString conversion treats -0 as 0.
+ if (!dval(&u)) {
+ signOut = false;
+ exponentOut = 0;
+ precisionOut = 1;
+ result[0] = '0';
+ result[1] = '\0';
+ return;
+ }
+
+ if (word0(&u) & Sign_bit) {
+ signOut = true;
+ word0(&u) &= ~Sign_bit; // clear sign bit
+ } else
+ signOut = false;
+
+ d2b(b, &u, &be, &bbits);
+ if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) {
+ dval(&d2) = dval(&u);
+ word0(&d2) &= Frac_mask1;
+ word0(&d2) |= Exp_11;
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+ denorm = 0;
+ } else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P - 1) - 1);
+ x = (i > 32) ? (word0(&u) << (64 - i)) | (word1(&u) >> (i - 32))
+ : word1(&u) << (32 - i);
+ dval(&d2) = x;
+ word0(&d2) -= 31 * Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P - 1) - 1) + 1;
+ denorm = 1;
+ }
+ ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981);
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(&u) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ } else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ } else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+
+ 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;
+ }
+
+ s = s0 = result;
+
+ if (ilim >= 0 && ilim <= Quick_max) {
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(&d2) = dval(&u);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k & 0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(&u) /= bigtens[n_bigtens - 1];
+ ieps++;
+ }
+ for (; j; j >>= 1, i++) {
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ }
+ dval(&u) /= ds;
+ } else if ((j1 = -k)) {
+ dval(&u) *= tens[j1 & 0xf];
+ for (j = j1 >> 4; j; j >>= 1, i++) {
+ if (j & 1) {
+ ieps++;
+ dval(&u) *= bigtens[i];
+ }
+ }
+ }
+ if (k_check && dval(&u) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fastFailed;
+ ilim = ilim1;
+ k--;
+ dval(&u) *= 10.;
+ ieps++;
+ }
+ dval(&eps) = (ieps * dval(&u)) + 7.;
+ word0(&eps) -= (P - 1) * Exp_msk1;
+ if (!ilim) {
+ S.clear();
+ mhi.clear();
+ dval(&u) -= 5.;
+ if (dval(&u) > dval(&eps))
+ goto oneDigit;
+ if (dval(&u) < -dval(&eps))
+ goto noDigits;
+ goto fastFailed;
+ }
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(&eps) = (0.5 / tens[ilim - 1]) - dval(&eps);
+ for (i = 0;;) {
+ L = (long int)dval(&u);
+ dval(&u) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(&u) < dval(&eps))
+ goto ret;
+ if (1. - dval(&u) < dval(&eps))
+ goto bumpUp;
+ if (++i >= ilim)
+ break;
+ dval(&eps) *= 10.;
+ dval(&u) *= 10.;
+ }
+ } else {
+ /* Generate ilim digits, then fix them up. */
+ dval(&eps) *= tens[ilim - 1];
+ for (i = 1;; i++, dval(&u) *= 10.) {
+ L = (int32_t)(dval(&u));
+ if (!(dval(&u) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(&u) > 0.5 + dval(&eps))
+ goto bumpUp;
+ if (dval(&u) < 0.5 - dval(&eps)) {
+ while (*--s == '0') { }
+ s++;
+ goto ret;
+ }
+ break;
+ }
+ }
+ }
+fastFailed:
+ s = s0;
+ dval(&u) = dval(&d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S.clear();
+ mhi.clear();
+ if (ilim < 0 || dval(&u) <= 5 * ds)
+ goto noDigits;
+ goto oneDigit;
+ }
+ for (i = 1;; i++, dval(&u) *= 10.) {
+ L = (int32_t)(dval(&u) / ds);
+ dval(&u) -= L * ds;
+ *s++ = '0' + (int)L;
+ if (!dval(&u)) {
+ break;
+ }
+ if (i == ilim) {
+ dval(&u) += dval(&u);
+ if (dval(&u) > ds || (dval(&u) == ds && (L & 1))) {
+bumpUp:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi.clear();
+ mlo.clear();
+ if (leftright) {
+ i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits;
+ b2 += i;
+ s2 += i;
+ i2b(mhi, 1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ pow5mult(mhi, m5);
+ mult(b, mhi);
+ }
+ if ((j = b5 - m5))
+ pow5mult(b, j);
+ } else
+ pow5mult(b, b5);
+ }
+ i2b(S, 1);
+ if (s5 > 0)
+ pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+ if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0x1f))
+ i = 32 - i;
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ } else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ lshift(b, b2);
+ if (s2 > 0)
+ lshift(S, s2);
+ if (k_check) {
+ if (cmp(b, S) < 0) {
+ k--;
+ multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ multadd(mhi, 10, 0);
+ 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);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case)
+ lshift(mhi, Log2P);
+
+ for (i = 1;;i++) {
+ 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);
+#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 round9up;
+ if (j > 0)
+ dig++;
+ *s++ = dig;
+ goto ret;
+ }
+ if (j < 0 || (!j && !(word1(&u) & 1))) {
+#endif
+ if ((b.words()[0] || b.size() > 1) && (j1 > 0)) {
+ lshift(b, 1);
+ j1 = cmp(b, S);
+ // 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++;
+ }
+ }
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+round9up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ multadd(b, 10, 0);
+ multadd(mlo, 10, 0);
+ multadd(mhi, 10, 0);
+ }
+ } else {
+ for (i = 1;; i++) {
+ *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);
+ // 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) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ } else {
+ while (*--s == '0') { }
+ s++;
+ }
+ goto ret;
+noDigits:
+ exponentOut = 0;
+ precisionOut = 1;
+ result[0] = '0';
+ result[1] = '\0';
+ return;
+oneDigit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ret:
+ ASSERT(s > result);
+ *s = 0;
+ exponentOut = k;
+ precisionOut = s - result;
+}
+
+void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision)
+{
+ // flags are roundingNone, leftright.
+ dtoa<true, false, false, true>(result, dd, 0, sign, exponent, precision);
+}
+
+void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
+{
+ // flag is roundingSignificantFigures.
+ dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision);
+}
+
+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);
+}
+
+const char* numberToString(double d, NumberToStringBuffer buffer)
+{
+ double_conversion::StringBuilder builder(buffer, NumberToStringBufferLength);
+ const double_conversion::DoubleToStringConverter& converter = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
+ converter.ToShortest(d, &builder);
+ return builder.Finalize();
+}
+
+static inline const char* formatStringTruncatingTrailingZerosIfNeeded(NumberToStringBuffer buffer, double_conversion::StringBuilder& builder)
+{
+ size_t length = builder.position();
+ size_t decimalPointPosition = 0;
+ for (; decimalPointPosition < length; ++decimalPointPosition) {
+ if (buffer[decimalPointPosition] == '.')
+ break;
+ }
+
+ // No decimal seperator found, early exit.
+ if (decimalPointPosition == length)
+ return builder.Finalize();
+
+ size_t truncatedLength = length - 1;
+ for (; truncatedLength > decimalPointPosition; --truncatedLength) {
+ if (buffer[truncatedLength] != '0')
+ break;
+ }
+
+ // No trailing zeros found to strip.
+ if (truncatedLength == length - 1)
+ return builder.Finalize();
+
+ // If we removed all trailing zeros, remove the decimal point as well.
+ if (truncatedLength == decimalPointPosition) {
+ ASSERT(truncatedLength > 0);
+ --truncatedLength;
+ }
+
+ // Truncate the StringBuilder, and return the final result.
+ builder.SetPosition(truncatedLength + 1);
+ return builder.Finalize();
+}
+
+const char* numberToFixedPrecisionString(double d, unsigned significantFigures, NumberToStringBuffer buffer, bool truncateTrailingZeros)
+{
+ // Mimic String::format("%.[precision]g", ...), but use dtoas rounding facilities.
+ // "g": Signed value printed in f or e format, whichever is more compact for the given value and precision.
+ // The e format is used only when the exponent of the value is less than –4 or greater than or equal to the
+ // precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
+ // "precision": The precision specifies the maximum number of significant digits printed.
+ double_conversion::StringBuilder builder(buffer, NumberToStringBufferLength);
+ const double_conversion::DoubleToStringConverter& converter = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
+ converter.ToPrecision(d, significantFigures, &builder);
+ if (!truncateTrailingZeros)
+ return builder.Finalize();
+ return formatStringTruncatingTrailingZerosIfNeeded(buffer, builder);
+}
+
+const char* numberToFixedWidthString(double d, unsigned decimalPlaces, NumberToStringBuffer buffer)
+{
+ // Mimic String::format("%.[precision]f", ...), but use dtoas rounding facilities.
+ // "f": Signed value having the form [ – ]dddd.dddd, where dddd is one or more decimal digits.
+ // The number of digits before the decimal point depends on the magnitude of the number, and
+ // the number of digits after the decimal point depends on the requested precision.
+ // "precision": The precision value specifies the number of digits after the decimal point.
+ // If a decimal point appears, at least one digit appears before it.
+ // The value is rounded to the appropriate number of digits.
+ double_conversion::StringBuilder builder(buffer, NumberToStringBufferLength);
+ const double_conversion::DoubleToStringConverter& converter = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
+ converter.ToFixed(d, decimalPlaces, &builder);
+ return builder.Finalize();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa.h b/Source/JavaScriptCore/wtf/dtoa.h
new file mode 100644
index 000000000..df33e2cdc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2003, 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 WTF_dtoa_h
+#define WTF_dtoa_h
+
+#include <wtf/dtoa/double-conversion.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WTF {
+class Mutex;
+
+extern WTF::Mutex* s_dtoaP5Mutex;
+
+typedef char DtoaBuffer[80];
+
+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);
+
+// 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);
+
+// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits.
+const unsigned NumberToStringBufferLength = 96;
+typedef char NumberToStringBuffer[NumberToStringBufferLength];
+typedef UChar NumberToUStringBuffer[NumberToStringBufferLength];
+const char* numberToString(double, NumberToStringBuffer);
+const char* numberToFixedPrecisionString(double, unsigned significantFigures, NumberToStringBuffer, bool truncateTrailingZeros = false);
+const char* numberToFixedWidthString(double, unsigned decimalPlaces, NumberToStringBuffer);
+
+} // namespace WTF
+
+using WTF::NumberToStringBuffer;
+using WTF::NumberToUStringBuffer;
+using WTF::numberToString;
+using WTF::numberToFixedPrecisionString;
+using WTF::numberToFixedWidthString;
+
+#endif // WTF_dtoa_h
diff --git a/Source/JavaScriptCore/wtf/dtoa/COPYING b/Source/JavaScriptCore/wtf/dtoa/COPYING
new file mode 100644
index 000000000..933718a9e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/COPYING
@@ -0,0 +1,26 @@
+Copyright 2006-2011, the V8 project authors. 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.
diff --git a/Source/JavaScriptCore/wtf/dtoa/LICENSE b/Source/JavaScriptCore/wtf/dtoa/LICENSE
new file mode 100644
index 000000000..933718a9e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2006-2011, the V8 project authors. 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.
diff --git a/Source/JavaScriptCore/wtf/dtoa/README b/Source/JavaScriptCore/wtf/dtoa/README
new file mode 100644
index 000000000..f186b420f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/README
@@ -0,0 +1,11 @@
+http://code.google.com/p/double-conversion
+
+This project (double-conversion) provides binary-decimal and decimal-binary
+routines for IEEE doubles.
+
+The library consists of efficient conversion routines that have been extracted
+from the V8 JavaScript engine. The code has been refactored and improved so that
+it can be used more easily in other projects.
+
+There is extensive documentation in src/double-conversion.h. Other examples can
+be found in test/cctest/test-conversions.cc.
diff --git a/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.cc b/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.cc
new file mode 100644
index 000000000..38be56c73
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.cc
@@ -0,0 +1,659 @@
+// Copyright 2010 the V8 project authors. 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 <math.h>
+
+#include "bignum-dtoa.h"
+
+#include "bignum.h"
+#include "double.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ static int NormalizedExponent(uint64_t significand, int exponent) {
+ ASSERT(significand != 0);
+ while ((significand & Double::kHiddenBit) == 0) {
+ significand = significand << 1;
+ exponent = exponent - 1;
+ }
+ return exponent;
+ }
+
+
+ // Forward declarations:
+ // Returns an estimation of k such that 10^(k-1) <= v < 10^k.
+ static int EstimatePower(int exponent);
+ // Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+ // and denominator.
+ static void InitialScaledStartValues(double v,
+ int estimated_power,
+ bool need_boundary_deltas,
+ Bignum* numerator,
+ Bignum* denominator,
+ Bignum* delta_minus,
+ Bignum* delta_plus);
+ // Multiplies numerator/denominator so that its values lies in the range 1-10.
+ // Returns decimal_point s.t.
+ // v = numerator'/denominator' * 10^(decimal_point-1)
+ // where numerator' and denominator' are the values of numerator and
+ // denominator after the call to this function.
+ static void FixupMultiply10(int estimated_power, bool is_even,
+ int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus);
+ // Generates digits from the left to the right and stops when the generated
+ // digits yield the shortest decimal representation of v.
+ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus,
+ bool is_even,
+ Vector<char> buffer, int* length);
+ // Generates 'requested_digits' after the decimal point.
+ static void BignumToFixed(int requested_digits, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char>(buffer), int* length);
+ // Generates 'count' digits of numerator/denominator.
+ // Once 'count' digits have been produced rounds the result depending on the
+ // remainder (remainders of exactly .5 round upwards). Might update the
+ // decimal_point when rounding up (for example for 0.9999).
+ static void GenerateCountedDigits(int count, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char>(buffer), int* length);
+
+
+ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+ Vector<char> buffer, int* length, int* decimal_point) {
+ ASSERT(v > 0);
+ ASSERT(!Double(v).IsSpecial());
+ uint64_t significand = Double(v).Significand();
+ bool is_even = (significand & 1) == 0;
+ int exponent = Double(v).Exponent();
+ int normalized_exponent = NormalizedExponent(significand, exponent);
+ // estimated_power might be too low by 1.
+ int estimated_power = EstimatePower(normalized_exponent);
+
+ // Shortcut for Fixed.
+ // The requested digits correspond to the digits after the point. If the
+ // number is much too small, then there is no need in trying to get any
+ // digits.
+ if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
+ buffer[0] = '\0';
+ *length = 0;
+ // Set decimal-point to -requested_digits. This is what Gay does.
+ // Note that it should not have any effect anyways since the string is
+ // empty.
+ *decimal_point = -requested_digits;
+ return;
+ }
+
+ Bignum numerator;
+ Bignum denominator;
+ Bignum delta_minus;
+ Bignum delta_plus;
+ // Make sure the bignum can grow large enough. The smallest double equals
+ // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+ // The maximum double is 1.7976931348623157e308 which needs fewer than
+ // 308*4 binary digits.
+ ASSERT(Bignum::kMaxSignificantBits >= 324*4);
+ bool need_boundary_deltas = (mode == BIGNUM_DTOA_SHORTEST);
+ InitialScaledStartValues(v, estimated_power, need_boundary_deltas,
+ &numerator, &denominator,
+ &delta_minus, &delta_plus);
+ // We now have v = (numerator / denominator) * 10^estimated_power.
+ FixupMultiply10(estimated_power, is_even, decimal_point,
+ &numerator, &denominator,
+ &delta_minus, &delta_plus);
+ // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+ // 1 <= (numerator + delta_plus) / denominator < 10
+ switch (mode) {
+ case BIGNUM_DTOA_SHORTEST:
+ GenerateShortestDigits(&numerator, &denominator,
+ &delta_minus, &delta_plus,
+ is_even, buffer, length);
+ break;
+ case BIGNUM_DTOA_FIXED:
+ BignumToFixed(requested_digits, decimal_point,
+ &numerator, &denominator,
+ buffer, length);
+ break;
+ case BIGNUM_DTOA_PRECISION:
+ GenerateCountedDigits(requested_digits, decimal_point,
+ &numerator, &denominator,
+ buffer, length);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ buffer[*length] = '\0';
+ }
+
+
+ // The procedure starts generating digits from the left to the right and stops
+ // when the generated digits yield the shortest decimal representation of v. A
+ // decimal representation of v is a number lying closer to v than to any other
+ // double, so it converts to v when read.
+ //
+ // This is true if d, the decimal representation, is between m- and m+, the
+ // upper and lower boundaries. d must be strictly between them if !is_even.
+ // m- := (numerator - delta_minus) / denominator
+ // m+ := (numerator + delta_plus) / denominator
+ //
+ // Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+ // If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+ // will be produced. This should be the standard precondition.
+ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus,
+ bool is_even,
+ Vector<char> buffer, int* length) {
+ // Small optimization: if delta_minus and delta_plus are the same just reuse
+ // one of the two bignums.
+ if (Bignum::Equal(*delta_minus, *delta_plus)) {
+ delta_plus = delta_minus;
+ }
+ *length = 0;
+ while (true) {
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
+ // digit = numerator / denominator (integer division).
+ // numerator = numerator % denominator.
+ buffer[(*length)++] = digit + '0';
+
+ // Can we stop already?
+ // If the remainder of the division is less than the distance to the lower
+ // boundary we can stop. In this case we simply round down (discarding the
+ // remainder).
+ // Similarly we test if we can round up (using the upper boundary).
+ bool in_delta_room_minus;
+ bool in_delta_room_plus;
+ if (is_even) {
+ in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
+ } else {
+ in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
+ }
+ if (is_even) {
+ in_delta_room_plus =
+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+ } else {
+ in_delta_room_plus =
+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+ }
+ if (!in_delta_room_minus && !in_delta_room_plus) {
+ // Prepare for next iteration.
+ numerator->Times10();
+ delta_minus->Times10();
+ // We optimized delta_plus to be equal to delta_minus (if they share the
+ // same value). So don't multiply delta_plus if they point to the same
+ // object.
+ if (delta_minus != delta_plus) {
+ delta_plus->Times10();
+ }
+ } else if (in_delta_room_minus && in_delta_room_plus) {
+ // Let's see if 2*numerator < denominator.
+ // If yes, then the next digit would be < 5 and we can round down.
+ int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
+ if (compare < 0) {
+ // Remaining digits are less than .5. -> Round down (== do nothing).
+ } else if (compare > 0) {
+ // Remaining digits are more than .5 of denominator. -> Round up.
+ // Note that the last digit could not be a '9' as otherwise the whole
+ // loop would have stopped earlier.
+ // We still have an assert here in case the preconditions were not
+ // satisfied.
+ ASSERT(buffer[(*length) - 1] != '9');
+ buffer[(*length) - 1]++;
+ } else {
+ // Halfway case.
+ // TODO(floitsch): need a way to solve half-way cases.
+ // For now let's round towards even (since this is what Gay seems to
+ // do).
+
+ if ((buffer[(*length) - 1] - '0') % 2 == 0) {
+ // Round down => Do nothing.
+ } else {
+ ASSERT(buffer[(*length) - 1] != '9');
+ buffer[(*length) - 1]++;
+ }
+ }
+ return;
+ } else if (in_delta_room_minus) {
+ // Round down (== do nothing).
+ return;
+ } else { // in_delta_room_plus
+ // Round up.
+ // Note again that the last digit could not be '9' since this would have
+ // stopped the loop earlier.
+ // We still have an ASSERT here, in case the preconditions were not
+ // satisfied.
+ ASSERT(buffer[(*length) -1] != '9');
+ buffer[(*length) - 1]++;
+ return;
+ }
+ }
+ }
+
+
+ // Let v = numerator / denominator < 10.
+ // Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+ // from left to right. Once 'count' digits have been produced we decide wether
+ // to round up or down. Remainders of exactly .5 round upwards. Numbers such
+ // as 9.999999 propagate a carry all the way, and change the
+ // exponent (decimal_point), when rounding upwards.
+ static void GenerateCountedDigits(int count, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char>(buffer), int* length) {
+ ASSERT(count >= 0);
+ for (int i = 0; i < count - 1; ++i) {
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
+ // digit = numerator / denominator (integer division).
+ // numerator = numerator % denominator.
+ buffer[i] = digit + '0';
+ // Prepare for next iteration.
+ numerator->Times10();
+ }
+ // Generate the last digit.
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+ digit++;
+ }
+ buffer[count - 1] = digit + '0';
+ // Correct bad digits (in case we had a sequence of '9's). Propagate the
+ // carry until we hat a non-'9' or til we reach the first digit.
+ for (int i = count - 1; i > 0; --i) {
+ if (buffer[i] != '0' + 10) break;
+ buffer[i] = '0';
+ buffer[i - 1]++;
+ }
+ if (buffer[0] == '0' + 10) {
+ // Propagate a carry past the top place.
+ buffer[0] = '1';
+ (*decimal_point)++;
+ }
+ *length = count;
+ }
+
+
+ // Generates 'requested_digits' after the decimal point. It might omit
+ // trailing '0's. If the input number is too small then no digits at all are
+ // generated (ex.: 2 fixed digits for 0.00001).
+ //
+ // Input verifies: 1 <= (numerator + delta) / denominator < 10.
+ static void BignumToFixed(int requested_digits, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char>(buffer), int* length) {
+ // Note that we have to look at more than just the requested_digits, since
+ // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+ // Even though the power of v equals 0 we can't just stop here.
+ if (-(*decimal_point) > requested_digits) {
+ // The number is definitively too small.
+ // Ex: 0.001 with requested_digits == 1.
+ // Set decimal-point to -requested_digits. This is what Gay does.
+ // Note that it should not have any effect anyways since the string is
+ // empty.
+ *decimal_point = -requested_digits;
+ *length = 0;
+ return;
+ } else if (-(*decimal_point) == requested_digits) {
+ // We only need to verify if the number rounds down or up.
+ // Ex: 0.04 and 0.06 with requested_digits == 1.
+ ASSERT(*decimal_point == -requested_digits);
+ // Initially the fraction lies in range (1, 10]. Multiply the denominator
+ // by 10 so that we can compare more easily.
+ denominator->Times10();
+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+ // If the fraction is >= 0.5 then we have to include the rounded
+ // digit.
+ buffer[0] = '1';
+ *length = 1;
+ (*decimal_point)++;
+ } else {
+ // Note that we caught most of similar cases earlier.
+ *length = 0;
+ }
+ return;
+ } else {
+ // The requested digits correspond to the digits after the point.
+ // The variable 'needed_digits' includes the digits before the point.
+ int needed_digits = (*decimal_point) + requested_digits;
+ GenerateCountedDigits(needed_digits, decimal_point,
+ numerator, denominator,
+ buffer, length);
+ }
+ }
+
+
+ // Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+ // v = f * 2^exponent and 2^52 <= f < 2^53.
+ // v is hence a normalized double with the given exponent. The output is an
+ // approximation for the exponent of the decimal approimation .digits * 10^k.
+ //
+ // The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+ // Note: this property holds for v's upper boundary m+ too.
+ // 10^k <= m+ < 10^k+1.
+ // (see explanation below).
+ //
+ // Examples:
+ // EstimatePower(0) => 16
+ // EstimatePower(-52) => 0
+ //
+ // Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+ static int EstimatePower(int exponent) {
+ // This function estimates log10 of v where v = f*2^e (with e == exponent).
+ // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+ // Note that f is bounded by its container size. Let p = 53 (the double's
+ // significand size). Then 2^(p-1) <= f < 2^p.
+ //
+ // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+ // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+ // The computed number undershoots by less than 0.631 (when we compute log3
+ // and not log10).
+ //
+ // Optimization: since we only need an approximated result this computation
+ // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+ // not really measurable, though.
+ //
+ // Since we want to avoid overshooting we decrement by 1e10 so that
+ // floating-point imprecisions don't affect us.
+ //
+ // Explanation for v's boundary m+: the computation takes advantage of
+ // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+ // (even for denormals where the delta can be much more important).
+
+ const double k1Log10 = 0.30102999566398114; // 1/lg(10)
+
+ // For doubles len(f) == 53 (don't forget the hidden bit).
+ const int kSignificandSize = 53;
+ double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+ return static_cast<int>(estimate);
+ }
+
+
+ // See comments for InitialScaledStartValues.
+ static void InitialScaledStartValuesPositiveExponent(
+ double v, int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ // A positive exponent implies a positive power.
+ ASSERT(estimated_power >= 0);
+ // Since the estimated_power is positive we simply multiply the denominator
+ // by 10^estimated_power.
+
+ // numerator = v.
+ numerator->AssignUInt64(Double(v).Significand());
+ numerator->ShiftLeft(Double(v).Exponent());
+ // denominator = 10^estimated_power.
+ denominator->AssignPowerUInt16(10, estimated_power);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ denominator->ShiftLeft(1);
+ numerator->ShiftLeft(1);
+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+ // denominator (of 2) delta_plus equals 2^e.
+ delta_plus->AssignUInt16(1);
+ delta_plus->ShiftLeft(Double(v).Exponent());
+ // Same for delta_minus (with adjustments below if f == 2^p-1).
+ delta_minus->AssignUInt16(1);
+ delta_minus->ShiftLeft(Double(v).Exponent());
+
+ // If the significand (without the hidden bit) is 0, then the lower
+ // boundary is closer than just half a ulp (unit in the last place).
+ // There is only one exception: if the next lower number is a denormal then
+ // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we
+ // have to test it in the other function where exponent < 0).
+ uint64_t v_bits = Double(v).AsUint64();
+ if ((v_bits & Double::kSignificandMask) == 0) {
+ // The lower boundary is closer at half the distance of "normal" numbers.
+ // Increase the common denominator and adapt all but the delta_minus.
+ denominator->ShiftLeft(1); // *2
+ numerator->ShiftLeft(1); // *2
+ delta_plus->ShiftLeft(1); // *2
+ }
+ }
+ }
+
+
+ // See comments for InitialScaledStartValues
+ static void InitialScaledStartValuesNegativeExponentPositivePower(
+ double v, int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ uint64_t significand = Double(v).Significand();
+ int exponent = Double(v).Exponent();
+ // v = f * 2^e with e < 0, and with estimated_power >= 0.
+ // This means that e is close to 0 (have a look at how estimated_power is
+ // computed).
+
+ // numerator = significand
+ // since v = significand * 2^exponent this is equivalent to
+ // numerator = v * / 2^-exponent
+ numerator->AssignUInt64(significand);
+ // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+ denominator->AssignPowerUInt16(10, estimated_power);
+ denominator->ShiftLeft(-exponent);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ denominator->ShiftLeft(1);
+ numerator->ShiftLeft(1);
+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+ // denominator (of 2) delta_plus equals 2^e.
+ // Given that the denominator already includes v's exponent the distance
+ // to the boundaries is simply 1.
+ delta_plus->AssignUInt16(1);
+ // Same for delta_minus (with adjustments below if f == 2^p-1).
+ delta_minus->AssignUInt16(1);
+
+ // If the significand (without the hidden bit) is 0, then the lower
+ // boundary is closer than just one ulp (unit in the last place).
+ // There is only one exception: if the next lower number is a denormal
+ // then the distance is 1 ulp. Since the exponent is close to zero
+ // (otherwise estimated_power would have been negative) this cannot happen
+ // here either.
+ uint64_t v_bits = Double(v).AsUint64();
+ if ((v_bits & Double::kSignificandMask) == 0) {
+ // The lower boundary is closer at half the distance of "normal" numbers.
+ // Increase the denominator and adapt all but the delta_minus.
+ denominator->ShiftLeft(1); // *2
+ numerator->ShiftLeft(1); // *2
+ delta_plus->ShiftLeft(1); // *2
+ }
+ }
+ }
+
+
+ // See comments for InitialScaledStartValues
+ static void InitialScaledStartValuesNegativeExponentNegativePower(
+ double v, int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ const uint64_t kMinimalNormalizedExponent =
+ UINT64_2PART_C(0x00100000, 00000000);
+ uint64_t significand = Double(v).Significand();
+ int exponent = Double(v).Exponent();
+ // Instead of multiplying the denominator with 10^estimated_power we
+ // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+ // Use numerator as temporary container for power_ten.
+ Bignum* power_ten = numerator;
+ power_ten->AssignPowerUInt16(10, -estimated_power);
+
+ if (need_boundary_deltas) {
+ // Since power_ten == numerator we must make a copy of 10^estimated_power
+ // before we complete the computation of the numerator.
+ // delta_plus = delta_minus = 10^estimated_power
+ delta_plus->AssignBignum(*power_ten);
+ delta_minus->AssignBignum(*power_ten);
+ }
+
+ // numerator = significand * 2 * 10^-estimated_power
+ // since v = significand * 2^exponent this is equivalent to
+ // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+ // Remember: numerator has been abused as power_ten. So no need to assign it
+ // to itself.
+ ASSERT(numerator == power_ten);
+ numerator->MultiplyByUInt64(significand);
+
+ // denominator = 2 * 2^-exponent with exponent < 0.
+ denominator->AssignUInt16(1);
+ denominator->ShiftLeft(-exponent);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ numerator->ShiftLeft(1);
+ denominator->ShiftLeft(1);
+ // With this shift the boundaries have their correct value, since
+ // delta_plus = 10^-estimated_power, and
+ // delta_minus = 10^-estimated_power.
+ // These assignments have been done earlier.
+
+ // The special case where the lower boundary is twice as close.
+ // This time we have to look out for the exception too.
+ uint64_t v_bits = Double(v).AsUint64();
+ if ((v_bits & Double::kSignificandMask) == 0 &&
+ // The only exception where a significand == 0 has its boundaries at
+ // "normal" distances:
+ (v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) {
+ numerator->ShiftLeft(1); // *2
+ denominator->ShiftLeft(1); // *2
+ delta_plus->ShiftLeft(1); // *2
+ }
+ }
+ }
+
+
+ // Let v = significand * 2^exponent.
+ // Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+ // and denominator. The functions GenerateShortestDigits and
+ // GenerateCountedDigits will then convert this ratio to its decimal
+ // representation d, with the required accuracy.
+ // Then d * 10^estimated_power is the representation of v.
+ // (Note: the fraction and the estimated_power might get adjusted before
+ // generating the decimal representation.)
+ //
+ // The initial start values consist of:
+ // - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+ // - a scaled (common) denominator.
+ // optionally (used by GenerateShortestDigits to decide if it has the shortest
+ // decimal converting back to v):
+ // - v - m-: the distance to the lower boundary.
+ // - m+ - v: the distance to the upper boundary.
+ //
+ // v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+ //
+ // Let ep == estimated_power, then the returned values will satisfy:
+ // v / 10^ep = numerator / denominator.
+ // v's boundarys m- and m+:
+ // m- / 10^ep == v / 10^ep - delta_minus / denominator
+ // m+ / 10^ep == v / 10^ep + delta_plus / denominator
+ // Or in other words:
+ // m- == v - delta_minus * 10^ep / denominator;
+ // m+ == v + delta_plus * 10^ep / denominator;
+ //
+ // Since 10^(k-1) <= v < 10^k (with k == estimated_power)
+ // or 10^k <= v < 10^(k+1)
+ // we then have 0.1 <= numerator/denominator < 1
+ // or 1 <= numerator/denominator < 10
+ //
+ // It is then easy to kickstart the digit-generation routine.
+ //
+ // The boundary-deltas are only filled if need_boundary_deltas is set.
+ static void InitialScaledStartValues(double v,
+ int estimated_power,
+ bool need_boundary_deltas,
+ Bignum* numerator,
+ Bignum* denominator,
+ Bignum* delta_minus,
+ Bignum* delta_plus) {
+ if (Double(v).Exponent() >= 0) {
+ InitialScaledStartValuesPositiveExponent(
+ v, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ } else if (estimated_power >= 0) {
+ InitialScaledStartValuesNegativeExponentPositivePower(
+ v, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ } else {
+ InitialScaledStartValuesNegativeExponentNegativePower(
+ v, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ }
+ }
+
+
+ // This routine multiplies numerator/denominator so that its values lies in the
+ // range 1-10. That is after a call to this function we have:
+ // 1 <= (numerator + delta_plus) /denominator < 10.
+ // Let numerator the input before modification and numerator' the argument
+ // after modification, then the output-parameter decimal_point is such that
+ // numerator / denominator * 10^estimated_power ==
+ // numerator' / denominator' * 10^(decimal_point - 1)
+ // In some cases estimated_power was too low, and this is already the case. We
+ // then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+ // estimated_power) but do not touch the numerator or denominator.
+ // Otherwise the routine multiplies the numerator and the deltas by 10.
+ static void FixupMultiply10(int estimated_power, bool is_even,
+ int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ bool in_range;
+ if (is_even) {
+ // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+ // are rounded to the closest floating-point number with even significand.
+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+ } else {
+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+ }
+ if (in_range) {
+ // Since numerator + delta_plus >= denominator we already have
+ // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+ *decimal_point = estimated_power + 1;
+ } else {
+ *decimal_point = estimated_power;
+ numerator->Times10();
+ if (Bignum::Equal(*delta_minus, *delta_plus)) {
+ delta_minus->Times10();
+ delta_plus->AssignBignum(*delta_minus);
+ } else {
+ delta_minus->Times10();
+ delta_plus->Times10();
+ }
+ }
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.h b/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.h
new file mode 100644
index 000000000..076168709
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/bignum-dtoa.h
@@ -0,0 +1,86 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ enum BignumDtoaMode {
+ // Return the shortest correct representation.
+ // For example the output of 0.299999999999999988897 is (the less accurate but
+ // correct) 0.3.
+ BIGNUM_DTOA_SHORTEST,
+ // Return a fixed number of digits after the decimal point.
+ // For instance fixed(0.1, 4) becomes 0.1000
+ // If the input number is big, the output will be big.
+ BIGNUM_DTOA_FIXED,
+ // Return a fixed number of digits, no matter what the exponent is.
+ BIGNUM_DTOA_PRECISION
+ };
+
+ // Converts the given double 'v' to ascii.
+ // The result should be interpreted as buffer * 10^(point-length).
+ // The buffer will be null-terminated.
+ //
+ // The input v must be > 0 and different from NaN, and Infinity.
+ //
+ // The output depends on the given mode:
+ // - SHORTEST: produce the least amount of digits for which the internal
+ // identity requirement is still satisfied. If the digits are printed
+ // (together with the correct exponent) then reading this number will give
+ // 'v' again. The buffer will choose the representation that is closest to
+ // 'v'. If there are two at the same distance, than the number is round up.
+ // In this mode the 'requested_digits' parameter is ignored.
+ // - FIXED: produces digits necessary to print a given number with
+ // 'requested_digits' digits after the decimal point. The produced digits
+ // might be too short in which case the caller has to fill the gaps with '0's.
+ // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+ // Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+ // buffer="2", point=0.
+ // Note: the length of the returned buffer has no meaning wrt the significance
+ // of its digits. That is, just because it contains '0's does not mean that
+ // any other digit would not satisfy the internal identity requirement.
+ // - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+ // Even though the length of produced digits usually equals
+ // 'requested_digits', the function is allowed to return fewer digits, in
+ // which case the caller has to fill the missing digits with '0's.
+ // Halfway cases are again rounded up.
+ // 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+ // and a terminating null-character.
+ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+ Vector<char> buffer, int* length, int* point);
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/bignum.cc b/Source/JavaScriptCore/wtf/dtoa/bignum.cc
new file mode 100644
index 000000000..46a900a85
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/bignum.cc
@@ -0,0 +1,770 @@
+// Copyright 2010 the V8 project authors. 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 "bignum.h"
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ Bignum::Bignum()
+ : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
+ for (int i = 0; i < kBigitCapacity; ++i) {
+ bigits_[i] = 0;
+ }
+ }
+
+
+ template<typename S>
+ static int BitSize(S value) {
+ return 8 * sizeof(value);
+ }
+
+ // Guaranteed to lie in one Bigit.
+ void Bignum::AssignUInt16(uint16_t value) {
+ ASSERT(kBigitSize >= BitSize(value));
+ Zero();
+ if (value == 0) return;
+
+ EnsureCapacity(1);
+ bigits_[0] = value;
+ used_digits_ = 1;
+ }
+
+
+ void Bignum::AssignUInt64(uint64_t value) {
+ const int kUInt64Size = 64;
+
+ Zero();
+ if (value == 0) return;
+
+ int needed_bigits = kUInt64Size / kBigitSize + 1;
+ EnsureCapacity(needed_bigits);
+ for (int i = 0; i < needed_bigits; ++i) {
+ bigits_[i] = (uint32_t)value & kBigitMask;
+ value = value >> kBigitSize;
+ }
+ used_digits_ = needed_bigits;
+ Clamp();
+ }
+
+
+ void Bignum::AssignBignum(const Bignum& other) {
+ exponent_ = other.exponent_;
+ for (int i = 0; i < other.used_digits_; ++i) {
+ bigits_[i] = other.bigits_[i];
+ }
+ // Clear the excess digits (if there were any).
+ for (int i = other.used_digits_; i < used_digits_; ++i) {
+ bigits_[i] = 0;
+ }
+ used_digits_ = other.used_digits_;
+ }
+
+
+ static uint64_t ReadUInt64(Vector<const char> buffer,
+ int from,
+ int digits_to_read) {
+ uint64_t result = 0;
+ for (int i = from; i < from + digits_to_read; ++i) {
+ int digit = buffer[i] - '0';
+ ASSERT(0 <= digit && digit <= 9);
+ result = result * 10 + digit;
+ }
+ return result;
+ }
+
+
+ void Bignum::AssignDecimalString(Vector<const char> value) {
+ // 2^64 = 18446744073709551616 > 10^19
+ const int kMaxUint64DecimalDigits = 19;
+ Zero();
+ int length = value.length();
+ int pos = 0;
+ // Let's just say that each digit needs 4 bits.
+ while (length >= kMaxUint64DecimalDigits) {
+ uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
+ pos += kMaxUint64DecimalDigits;
+ length -= kMaxUint64DecimalDigits;
+ MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
+ AddUInt64(digits);
+ }
+ uint64_t digits = ReadUInt64(value, pos, length);
+ MultiplyByPowerOfTen(length);
+ AddUInt64(digits);
+ Clamp();
+ }
+
+
+ static int HexCharValue(char c) {
+ if ('0' <= c && c <= '9') return c - '0';
+ if ('a' <= c && c <= 'f') return 10 + c - 'a';
+ if ('A' <= c && c <= 'F') return 10 + c - 'A';
+ UNREACHABLE();
+ return 0; // To make compiler happy.
+ }
+
+
+ void Bignum::AssignHexString(Vector<const char> value) {
+ Zero();
+ int length = value.length();
+
+ int needed_bigits = length * 4 / kBigitSize + 1;
+ EnsureCapacity(needed_bigits);
+ int string_index = length - 1;
+ for (int i = 0; i < needed_bigits - 1; ++i) {
+ // These bigits are guaranteed to be "full".
+ Chunk current_bigit = 0;
+ for (int j = 0; j < kBigitSize / 4; j++) {
+ current_bigit += HexCharValue(value[string_index--]) << (j * 4);
+ }
+ bigits_[i] = current_bigit;
+ }
+ used_digits_ = needed_bigits - 1;
+
+ Chunk most_significant_bigit = 0; // Could be = 0;
+ for (int j = 0; j <= string_index; ++j) {
+ most_significant_bigit <<= 4;
+ most_significant_bigit += HexCharValue(value[j]);
+ }
+ if (most_significant_bigit != 0) {
+ bigits_[used_digits_] = most_significant_bigit;
+ used_digits_++;
+ }
+ Clamp();
+ }
+
+
+ void Bignum::AddUInt64(uint64_t operand) {
+ if (operand == 0) return;
+ Bignum other;
+ other.AssignUInt64(operand);
+ AddBignum(other);
+ }
+
+
+ void Bignum::AddBignum(const Bignum& other) {
+ ASSERT(IsClamped());
+ ASSERT(other.IsClamped());
+
+ // If this has a greater exponent than other append zero-bigits to this.
+ // After this call exponent_ <= other.exponent_.
+ Align(other);
+
+ // There are two possibilities:
+ // aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
+ // bbbbb 00000000
+ // ----------------
+ // ccccccccccc 0000
+ // or
+ // aaaaaaaaaa 0000
+ // bbbbbbbbb 0000000
+ // -----------------
+ // cccccccccccc 0000
+ // In both cases we might need a carry bigit.
+
+ EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
+ Chunk carry = 0;
+ int bigit_pos = other.exponent_ - exponent_;
+ ASSERT(bigit_pos >= 0);
+ for (int i = 0; i < other.used_digits_; ++i) {
+ Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+ bigits_[bigit_pos] = sum & kBigitMask;
+ carry = sum >> kBigitSize;
+ bigit_pos++;
+ }
+
+ while (carry != 0) {
+ Chunk sum = bigits_[bigit_pos] + carry;
+ bigits_[bigit_pos] = sum & kBigitMask;
+ carry = sum >> kBigitSize;
+ bigit_pos++;
+ }
+ used_digits_ = Max(bigit_pos, used_digits_);
+ ASSERT(IsClamped());
+ }
+
+
+ void Bignum::SubtractBignum(const Bignum& other) {
+ ASSERT(IsClamped());
+ ASSERT(other.IsClamped());
+ // We require this to be bigger than other.
+ ASSERT(LessEqual(other, *this));
+
+ Align(other);
+
+ int offset = other.exponent_ - exponent_;
+ Chunk borrow = 0;
+ int i;
+ for (i = 0; i < other.used_digits_; ++i) {
+ ASSERT((borrow == 0) || (borrow == 1));
+ Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+ bigits_[i + offset] = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ }
+ while (borrow != 0) {
+ Chunk difference = bigits_[i + offset] - borrow;
+ bigits_[i + offset] = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ ++i;
+ }
+ Clamp();
+ }
+
+
+ void Bignum::ShiftLeft(int shift_amount) {
+ if (used_digits_ == 0) return;
+ exponent_ += shift_amount / kBigitSize;
+ int local_shift = shift_amount % kBigitSize;
+ EnsureCapacity(used_digits_ + 1);
+ BigitsShiftLeft(local_shift);
+ }
+
+
+ void Bignum::MultiplyByUInt32(uint32_t factor) {
+ if (factor == 1) return;
+ if (factor == 0) {
+ Zero();
+ return;
+ }
+ if (used_digits_ == 0) return;
+
+ // The product of a bigit with the factor is of size kBigitSize + 32.
+ // Assert that this number + 1 (for the carry) fits into double chunk.
+ ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
+ DoubleChunk carry = 0;
+ for (int i = 0; i < used_digits_; ++i) {
+ DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
+ bigits_[i] = static_cast<Chunk>(product & kBigitMask);
+ carry = (product >> kBigitSize);
+ }
+ while (carry != 0) {
+ EnsureCapacity(used_digits_ + 1);
+ bigits_[used_digits_] = (uint32_t)carry & kBigitMask;
+ used_digits_++;
+ carry >>= kBigitSize;
+ }
+ }
+
+
+ void Bignum::MultiplyByUInt64(uint64_t factor) {
+ if (factor == 1) return;
+ if (factor == 0) {
+ Zero();
+ return;
+ }
+ ASSERT(kBigitSize < 32);
+ uint64_t carry = 0;
+ uint64_t low = factor & 0xFFFFFFFF;
+ uint64_t high = factor >> 32;
+ for (int i = 0; i < used_digits_; ++i) {
+ uint64_t product_low = low * bigits_[i];
+ uint64_t product_high = high * bigits_[i];
+ uint64_t tmp = (carry & kBigitMask) + product_low;
+ bigits_[i] = (uint32_t)tmp & kBigitMask;
+ carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
+ (product_high << (32 - kBigitSize));
+ }
+ while (carry != 0) {
+ EnsureCapacity(used_digits_ + 1);
+ bigits_[used_digits_] = (uint32_t)carry & kBigitMask;
+ used_digits_++;
+ carry >>= kBigitSize;
+ }
+ }
+
+
+ void Bignum::MultiplyByPowerOfTen(int exponent) {
+ const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d);
+ const uint16_t kFive1 = 5;
+ const uint16_t kFive2 = kFive1 * 5;
+ const uint16_t kFive3 = kFive2 * 5;
+ const uint16_t kFive4 = kFive3 * 5;
+ const uint16_t kFive5 = kFive4 * 5;
+ const uint16_t kFive6 = kFive5 * 5;
+ const uint32_t kFive7 = kFive6 * 5;
+ const uint32_t kFive8 = kFive7 * 5;
+ const uint32_t kFive9 = kFive8 * 5;
+ const uint32_t kFive10 = kFive9 * 5;
+ const uint32_t kFive11 = kFive10 * 5;
+ const uint32_t kFive12 = kFive11 * 5;
+ const uint32_t kFive13 = kFive12 * 5;
+ const uint32_t kFive1_to_12[] =
+ { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+ kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+ ASSERT(exponent >= 0);
+ if (exponent == 0) return;
+ if (used_digits_ == 0) return;
+
+ // We shift by exponent at the end just before returning.
+ int remaining_exponent = exponent;
+ while (remaining_exponent >= 27) {
+ MultiplyByUInt64(kFive27);
+ remaining_exponent -= 27;
+ }
+ while (remaining_exponent >= 13) {
+ MultiplyByUInt32(kFive13);
+ remaining_exponent -= 13;
+ }
+ if (remaining_exponent > 0) {
+ MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+ }
+ ShiftLeft(exponent);
+ }
+
+
+ void Bignum::Square() {
+ ASSERT(IsClamped());
+ int product_length = 2 * used_digits_;
+ EnsureCapacity(product_length);
+
+ // Comba multiplication: compute each column separately.
+ // Example: r = a2a1a0 * b2b1b0.
+ // r = 1 * a0b0 +
+ // 10 * (a1b0 + a0b1) +
+ // 100 * (a2b0 + a1b1 + a0b2) +
+ // 1000 * (a2b1 + a1b2) +
+ // 10000 * a2b2
+ //
+ // In the worst case we have to accumulate nb-digits products of digit*digit.
+ //
+ // Assert that the additional number of bits in a DoubleChunk are enough to
+ // sum up used_digits of Bigit*Bigit.
+ if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+ UNIMPLEMENTED();
+ }
+ DoubleChunk accumulator = 0;
+ // First shift the digits so we don't overwrite them.
+ int copy_offset = used_digits_;
+ for (int i = 0; i < used_digits_; ++i) {
+ bigits_[copy_offset + i] = bigits_[i];
+ }
+ // We have two loops to avoid some 'if's in the loop.
+ for (int i = 0; i < used_digits_; ++i) {
+ // Process temporary digit i with power i.
+ // The sum of the two indices must be equal to i.
+ int bigit_index1 = i;
+ int bigit_index2 = 0;
+ // Sum all of the sub-products.
+ while (bigit_index1 >= 0) {
+ Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+ Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+ bigit_index1--;
+ bigit_index2++;
+ }
+ bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+ accumulator >>= kBigitSize;
+ }
+ for (int i = used_digits_; i < product_length; ++i) {
+ int bigit_index1 = used_digits_ - 1;
+ int bigit_index2 = i - bigit_index1;
+ // Invariant: sum of both indices is again equal to i.
+ // Inner loop runs 0 times on last iteration, emptying accumulator.
+ while (bigit_index2 < used_digits_) {
+ Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+ Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+ bigit_index1--;
+ bigit_index2++;
+ }
+ // The overwritten bigits_[i] will never be read in further loop iterations,
+ // because bigit_index1 and bigit_index2 are always greater
+ // than i - used_digits_.
+ bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+ accumulator >>= kBigitSize;
+ }
+ // Since the result was guaranteed to lie inside the number the
+ // accumulator must be 0 now.
+ ASSERT(accumulator == 0);
+
+ // Don't forget to update the used_digits and the exponent.
+ used_digits_ = product_length;
+ exponent_ *= 2;
+ Clamp();
+ }
+
+
+ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
+ ASSERT(base != 0);
+ ASSERT(power_exponent >= 0);
+ if (power_exponent == 0) {
+ AssignUInt16(1);
+ return;
+ }
+ Zero();
+ int shifts = 0;
+ // We expect base to be in range 2-32, and most often to be 10.
+ // It does not make much sense to implement different algorithms for counting
+ // the bits.
+ while ((base & 1) == 0) {
+ base >>= 1;
+ shifts++;
+ }
+ int bit_size = 0;
+ int tmp_base = base;
+ while (tmp_base != 0) {
+ tmp_base >>= 1;
+ bit_size++;
+ }
+ int final_size = bit_size * power_exponent;
+ // 1 extra bigit for the shifting, and one for rounded final_size.
+ EnsureCapacity(final_size / kBigitSize + 2);
+
+ // Left to Right exponentiation.
+ int mask = 1;
+ while (power_exponent >= mask) mask <<= 1;
+
+ // The mask is now pointing to the bit above the most significant 1-bit of
+ // power_exponent.
+ // Get rid of first 1-bit;
+ mask >>= 2;
+ uint64_t this_value = base;
+
+ bool delayed_multipliciation = false;
+ const uint64_t max_32bits = 0xFFFFFFFF;
+ while (mask != 0 && this_value <= max_32bits) {
+ this_value = this_value * this_value;
+ // Verify that there is enough space in this_value to perform the
+ // multiplication. The first bit_size bits must be 0.
+ if ((power_exponent & mask) != 0) {
+ uint64_t base_bits_mask =
+ ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
+ bool high_bits_zero = (this_value & base_bits_mask) == 0;
+ if (high_bits_zero) {
+ this_value *= base;
+ } else {
+ delayed_multipliciation = true;
+ }
+ }
+ mask >>= 1;
+ }
+ AssignUInt64(this_value);
+ if (delayed_multipliciation) {
+ MultiplyByUInt32(base);
+ }
+
+ // Now do the same thing as a bignum.
+ while (mask != 0) {
+ Square();
+ if ((power_exponent & mask) != 0) {
+ MultiplyByUInt32(base);
+ }
+ mask >>= 1;
+ }
+
+ // And finally add the saved shifts.
+ ShiftLeft(shifts * power_exponent);
+ }
+
+
+ // Precondition: this/other < 16bit.
+ uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
+ ASSERT(IsClamped());
+ ASSERT(other.IsClamped());
+ ASSERT(other.used_digits_ > 0);
+
+ // Easy case: if we have less digits than the divisor than the result is 0.
+ // Note: this handles the case where this == 0, too.
+ if (BigitLength() < other.BigitLength()) {
+ return 0;
+ }
+
+ Align(other);
+
+ uint16_t result = 0;
+
+ // Start by removing multiples of 'other' until both numbers have the same
+ // number of digits.
+ while (BigitLength() > other.BigitLength()) {
+ // This naive approach is extremely inefficient if the this divided other
+ // might be big. This function is implemented for doubleToString where
+ // the result should be small (less than 10).
+ ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+ // Remove the multiples of the first digit.
+ // Example this = 23 and other equals 9. -> Remove 2 multiples.
+ result += bigits_[used_digits_ - 1];
+ SubtractTimes(other, bigits_[used_digits_ - 1]);
+ }
+
+ ASSERT(BigitLength() == other.BigitLength());
+
+ // Both bignums are at the same length now.
+ // Since other has more than 0 digits we know that the access to
+ // bigits_[used_digits_ - 1] is safe.
+ Chunk this_bigit = bigits_[used_digits_ - 1];
+ Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
+
+ if (other.used_digits_ == 1) {
+ // Shortcut for easy (and common) case.
+ int quotient = this_bigit / other_bigit;
+ bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+ result += quotient;
+ Clamp();
+ return result;
+ }
+
+ int division_estimate = this_bigit / (other_bigit + 1);
+ result += division_estimate;
+ SubtractTimes(other, division_estimate);
+
+ if (other_bigit * (division_estimate + 1) > this_bigit) {
+ // No need to even try to subtract. Even if other's remaining digits were 0
+ // another subtraction would be too much.
+ return result;
+ }
+
+ while (LessEqual(other, *this)) {
+ SubtractBignum(other);
+ result++;
+ }
+ return result;
+ }
+
+
+ template<typename S>
+ static int SizeInHexChars(S number) {
+ ASSERT(number > 0);
+ int result = 0;
+ while (number != 0) {
+ number >>= 4;
+ result++;
+ }
+ return result;
+ }
+
+
+ static char HexCharOfValue(int value) {
+ ASSERT(0 <= value && value <= 16);
+ if (value < 10) return value + '0';
+ return value - 10 + 'A';
+ }
+
+
+ bool Bignum::ToHexString(char* buffer, int buffer_size) const {
+ ASSERT(IsClamped());
+ // Each bigit must be printable as separate hex-character.
+ ASSERT(kBigitSize % 4 == 0);
+ const int kHexCharsPerBigit = kBigitSize / 4;
+
+ if (used_digits_ == 0) {
+ if (buffer_size < 2) return false;
+ buffer[0] = '0';
+ buffer[1] = '\0';
+ return true;
+ }
+ // We add 1 for the terminating '\0' character.
+ int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
+ SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
+ if (needed_chars > buffer_size) return false;
+ int string_index = needed_chars - 1;
+ buffer[string_index--] = '\0';
+ for (int i = 0; i < exponent_; ++i) {
+ for (int j = 0; j < kHexCharsPerBigit; ++j) {
+ buffer[string_index--] = '0';
+ }
+ }
+ for (int i = 0; i < used_digits_ - 1; ++i) {
+ Chunk current_bigit = bigits_[i];
+ for (int j = 0; j < kHexCharsPerBigit; ++j) {
+ buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
+ current_bigit >>= 4;
+ }
+ }
+ // And finally the last bigit.
+ Chunk most_significant_bigit = bigits_[used_digits_ - 1];
+ while (most_significant_bigit != 0) {
+ buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
+ most_significant_bigit >>= 4;
+ }
+ return true;
+ }
+
+
+ Bignum::Chunk Bignum::BigitAt(int index) const {
+ if (index >= BigitLength()) return 0;
+ if (index < exponent_) return 0;
+ return bigits_[index - exponent_];
+ }
+
+
+ int Bignum::Compare(const Bignum& a, const Bignum& b) {
+ ASSERT(a.IsClamped());
+ ASSERT(b.IsClamped());
+ int bigit_length_a = a.BigitLength();
+ int bigit_length_b = b.BigitLength();
+ if (bigit_length_a < bigit_length_b) return -1;
+ if (bigit_length_a > bigit_length_b) return +1;
+ for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
+ Chunk bigit_a = a.BigitAt(i);
+ Chunk bigit_b = b.BigitAt(i);
+ if (bigit_a < bigit_b) return -1;
+ if (bigit_a > bigit_b) return +1;
+ // Otherwise they are equal up to this digit. Try the next digit.
+ }
+ return 0;
+ }
+
+
+ int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
+ ASSERT(a.IsClamped());
+ ASSERT(b.IsClamped());
+ ASSERT(c.IsClamped());
+ if (a.BigitLength() < b.BigitLength()) {
+ return PlusCompare(b, a, c);
+ }
+ if (a.BigitLength() + 1 < c.BigitLength()) return -1;
+ if (a.BigitLength() > c.BigitLength()) return +1;
+ // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+ // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+ // of 'a'.
+ if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
+ return -1;
+ }
+
+ Chunk borrow = 0;
+ // Starting at min_exponent all digits are == 0. So no need to compare them.
+ int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
+ for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
+ Chunk chunk_a = a.BigitAt(i);
+ Chunk chunk_b = b.BigitAt(i);
+ Chunk chunk_c = c.BigitAt(i);
+ Chunk sum = chunk_a + chunk_b;
+ if (sum > chunk_c + borrow) {
+ return +1;
+ } else {
+ borrow = chunk_c + borrow - sum;
+ if (borrow > 1) return -1;
+ borrow <<= kBigitSize;
+ }
+ }
+ if (borrow == 0) return 0;
+ return -1;
+ }
+
+
+ void Bignum::Clamp() {
+ while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+ used_digits_--;
+ }
+ if (used_digits_ == 0) {
+ // Zero.
+ exponent_ = 0;
+ }
+ }
+
+
+ bool Bignum::IsClamped() const {
+ return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+ }
+
+
+ void Bignum::Zero() {
+ for (int i = 0; i < used_digits_; ++i) {
+ bigits_[i] = 0;
+ }
+ used_digits_ = 0;
+ exponent_ = 0;
+ }
+
+
+ void Bignum::Align(const Bignum& other) {
+ if (exponent_ > other.exponent_) {
+ // If "X" represents a "hidden" digit (by the exponent) then we are in the
+ // following case (a == this, b == other):
+ // a: aaaaaaXXXX or a: aaaaaXXX
+ // b: bbbbbbX b: bbbbbbbbXX
+ // We replace some of the hidden digits (X) of a with 0 digits.
+ // a: aaaaaa000X or a: aaaaa0XX
+ int zero_digits = exponent_ - other.exponent_;
+ EnsureCapacity(used_digits_ + zero_digits);
+ for (int i = used_digits_ - 1; i >= 0; --i) {
+ bigits_[i + zero_digits] = bigits_[i];
+ }
+ for (int i = 0; i < zero_digits; ++i) {
+ bigits_[i] = 0;
+ }
+ used_digits_ += zero_digits;
+ exponent_ -= zero_digits;
+ ASSERT(used_digits_ >= 0);
+ ASSERT(exponent_ >= 0);
+ }
+ }
+
+
+ void Bignum::BigitsShiftLeft(int shift_amount) {
+ ASSERT(shift_amount < kBigitSize);
+ ASSERT(shift_amount >= 0);
+ Chunk carry = 0;
+ for (int i = 0; i < used_digits_; ++i) {
+ Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
+ bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+ carry = new_carry;
+ }
+ if (carry != 0) {
+ bigits_[used_digits_] = carry;
+ used_digits_++;
+ }
+ }
+
+
+ void Bignum::SubtractTimes(const Bignum& other, int factor) {
+ ASSERT(exponent_ <= other.exponent_);
+ if (factor < 3) {
+ for (int i = 0; i < factor; ++i) {
+ SubtractBignum(other);
+ }
+ return;
+ }
+ Chunk borrow = 0;
+ int exponent_diff = other.exponent_ - exponent_;
+ for (int i = 0; i < other.used_digits_; ++i) {
+ DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
+ DoubleChunk remove = borrow + product;
+ Chunk difference = bigits_[i + exponent_diff] - ((uint32_t)remove & kBigitMask);
+ bigits_[i + exponent_diff] = difference & kBigitMask;
+ borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
+ (remove >> kBigitSize));
+ }
+ for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+ if (borrow == 0) return;
+ Chunk difference = bigits_[i] - borrow;
+ bigits_[i] = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ ++i;
+ }
+ Clamp();
+ }
+
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/bignum.h b/Source/JavaScriptCore/wtf/dtoa/bignum.h
new file mode 100644
index 000000000..1a750581a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/bignum.h
@@ -0,0 +1,145 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_BIGNUM_H_
+#define DOUBLE_CONVERSION_BIGNUM_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ class Bignum {
+ public:
+ // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+ // This bignum can encode much bigger numbers, since it contains an
+ // exponent.
+ static const int kMaxSignificantBits = 3584;
+
+ Bignum();
+ void AssignUInt16(uint16_t value);
+ void AssignUInt64(uint64_t value);
+ void AssignBignum(const Bignum& other);
+
+ void AssignDecimalString(Vector<const char> value);
+ void AssignHexString(Vector<const char> value);
+
+ void AssignPowerUInt16(uint16_t base, int exponent);
+
+ void AddUInt16(uint16_t operand);
+ void AddUInt64(uint64_t operand);
+ void AddBignum(const Bignum& other);
+ // Precondition: this >= other.
+ void SubtractBignum(const Bignum& other);
+
+ void Square();
+ void ShiftLeft(int shift_amount);
+ void MultiplyByUInt32(uint32_t factor);
+ void MultiplyByUInt64(uint64_t factor);
+ void MultiplyByPowerOfTen(int exponent);
+ void Times10() { return MultiplyByUInt32(10); }
+ // Pseudocode:
+ // int result = this / other;
+ // this = this % other;
+ // In the worst case this function is in O(this/other).
+ uint16_t DivideModuloIntBignum(const Bignum& other);
+
+ bool ToHexString(char* buffer, int buffer_size) const;
+
+ static int Compare(const Bignum& a, const Bignum& b);
+ static bool Equal(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) == 0;
+ }
+ static bool LessEqual(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) <= 0;
+ }
+ static bool Less(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) < 0;
+ }
+ // Returns Compare(a + b, c);
+ static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
+ // Returns a + b == c
+ static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) == 0;
+ }
+ // Returns a + b <= c
+ static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) <= 0;
+ }
+ // Returns a + b < c
+ static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) < 0;
+ }
+ private:
+ typedef uint32_t Chunk;
+ typedef uint64_t DoubleChunk;
+
+ static const int kChunkSize = sizeof(Chunk) * 8;
+ static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
+ // With bigit size of 28 we loose some bits, but a double still fits easily
+ // into two chunks, and more importantly we can use the Comba multiplication.
+ static const int kBigitSize = 28;
+ static const Chunk kBigitMask = (1 << kBigitSize) - 1;
+ // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
+ // grow. There are no checks if the stack-allocated space is sufficient.
+ static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+ void EnsureCapacity(int size) {
+ if (size > kBigitCapacity) {
+ UNREACHABLE();
+ }
+ }
+ void Align(const Bignum& other);
+ void Clamp();
+ bool IsClamped() const;
+ void Zero();
+ // Requires this to have enough capacity (no tests done).
+ // Updates used_digits_ if necessary.
+ // shift_amount must be < kBigitSize.
+ void BigitsShiftLeft(int shift_amount);
+ // BigitLength includes the "hidden" digits encoded in the exponent.
+ int BigitLength() const { return used_digits_ + exponent_; }
+ Chunk BigitAt(int index) const;
+ void SubtractTimes(const Bignum& other, int factor);
+
+ Chunk bigits_buffer_[kBigitCapacity];
+ // A vector backed by bigits_buffer_. This way accesses to the array are
+ // checked for out-of-bounds errors.
+ Vector<Chunk> bigits_;
+ int used_digits_;
+ // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+ int exponent_;
+
+ DISALLOW_COPY_AND_ASSIGN(Bignum);
+ };
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_BIGNUM_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/cached-powers.cc b/Source/JavaScriptCore/wtf/dtoa/cached-powers.cc
new file mode 100644
index 000000000..54cb7cadd
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/cached-powers.cc
@@ -0,0 +1,193 @@
+// Copyright 2006-2008 the V8 project authors. 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 <stdarg.h>
+#include <limits.h>
+#include <math.h>
+
+#include "UnusedParam.h"
+#include "utils.h"
+#include "cached-powers.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ struct CachedPower {
+ uint64_t significand;
+ int16_t binary_exponent;
+ int16_t decimal_exponent;
+ };
+
+ static int kCachedPowersLength = 1;
+ static int kCachedPowersOffset = 1;
+ static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
+ static CachedPower* kCachedPowers = 0;
+
+ int PowersOfTenCache::kDecimalExponentDistance = 1;
+ int PowersOfTenCache::kMinDecimalExponent = 1;
+ int PowersOfTenCache::kMaxDecimalExponent = 1;
+
+ void initialize() {
+ if (kCachedPowers)
+ return;
+ static CachedPower cachedPowers[] = {
+ {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},
+ {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},
+ {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},
+ {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},
+ {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},
+ {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},
+ {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},
+ {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},
+ {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},
+ {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},
+ {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},
+ {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},
+ {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},
+ {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},
+ {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},
+ {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},
+ {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},
+ {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},
+ {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},
+ {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},
+ {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},
+ {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},
+ {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},
+ {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},
+ {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},
+ {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+ {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},
+ {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},
+ {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},
+ {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},
+ {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},
+ {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},
+ {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+ {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},
+ {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},
+ {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},
+ {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},
+ {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},
+ {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},
+ {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},
+ {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},
+ {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},
+ {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},
+ {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},
+ {UINT64_2PART_C(0x9c400000, 00000000), -50, 4},
+ {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},
+ {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},
+ {UINT64_2PART_C(0x813f3978, f8940984), 30, 28},
+ {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},
+ {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},
+ {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},
+ {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},
+ {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},
+ {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},
+ {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},
+ {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},
+ {UINT64_2PART_C(0x924d692c, a61be758), 269, 100},
+ {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},
+ {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},
+ {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},
+ {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},
+ {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},
+ {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},
+ {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},
+ {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},
+ {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},
+ {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},
+ {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},
+ {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},
+ {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},
+ {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},
+ {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},
+ {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},
+ {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},
+ {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},
+ {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},
+ {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},
+ {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},
+ {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},
+ {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},
+ {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},
+ {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},
+ {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},
+ {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},
+ {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},
+ {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},
+ {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+ };
+ kCachedPowers = cachedPowers;
+ kCachedPowersLength = ARRAY_SIZE(cachedPowers);
+ kCachedPowersOffset = -cachedPowers[0].decimal_exponent;
+ PowersOfTenCache::kDecimalExponentDistance = kCachedPowers[1].decimal_exponent - kCachedPowers[0].decimal_exponent;
+ PowersOfTenCache::kMinDecimalExponent = kCachedPowers[0].decimal_exponent;
+ PowersOfTenCache::kMaxDecimalExponent = kCachedPowers[kCachedPowersLength - 1].decimal_exponent;
+ }
+
+ void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+ int min_exponent,
+ int max_exponent,
+ DiyFp* power,
+ int* decimal_exponent) {
+ UNUSED_PARAM(max_exponent);
+ int kQ = DiyFp::kSignificandSize;
+ double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
+ int foo = kCachedPowersOffset;
+ int index =
+ (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
+ ASSERT(0 <= index && index < kCachedPowersLength);
+ CachedPower cached_power = kCachedPowers[index];
+ ASSERT(min_exponent <= cached_power.binary_exponent);
+ ASSERT(cached_power.binary_exponent <= max_exponent);
+ *decimal_exponent = cached_power.decimal_exponent;
+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+ }
+
+
+ void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent,
+ DiyFp* power,
+ int* found_exponent) {
+ ASSERT(kMinDecimalExponent <= requested_exponent);
+ ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
+ int index =
+ (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
+ CachedPower cached_power = kCachedPowers[index];
+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+ *found_exponent = cached_power.decimal_exponent;
+ ASSERT(*found_exponent <= requested_exponent);
+ ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/cached-powers.h b/Source/JavaScriptCore/wtf/dtoa/cached-powers.h
new file mode 100644
index 000000000..cbc04d43d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/cached-powers.h
@@ -0,0 +1,72 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_CACHED_POWERS_H_
+#define DOUBLE_CONVERSION_CACHED_POWERS_H_
+
+#include "diy-fp.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ class PowersOfTenCache {
+ public:
+
+ // Not all powers of ten are cached. The decimal exponent of two neighboring
+ // cached numbers will differ by kDecimalExponentDistance.
+ static int kDecimalExponentDistance;
+
+ static int kMinDecimalExponent;
+ static int kMaxDecimalExponent;
+
+ // Returns a cached power-of-ten with a binary exponent in the range
+ // [min_exponent; max_exponent] (boundaries included).
+ static void GetCachedPowerForBinaryExponentRange(int min_exponent,
+ int max_exponent,
+ DiyFp* power,
+ int* decimal_exponent);
+
+ // Returns a cached power of ten x ~= 10^k such that
+ // k <= decimal_exponent < k + kCachedPowersDecimalDistance.
+ // The given decimal_exponent must satisfy
+ // kMinDecimalExponent <= requested_exponent, and
+ // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.
+ static void GetCachedPowerForDecimalExponent(int requested_exponent,
+ DiyFp* power,
+ int* found_exponent);
+ };
+
+ // Initializes the table of cached powers used by the dtoa algorithm.
+ // This needs to be called when JSC is being initialized.
+ void initialize();
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/diy-fp.cc b/Source/JavaScriptCore/wtf/dtoa/diy-fp.cc
new file mode 100644
index 000000000..c0233595f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/diy-fp.cc
@@ -0,0 +1,62 @@
+// Copyright 2010 the V8 project authors. 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 "diy-fp.h"
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ void DiyFp::Multiply(const DiyFp& other) {
+ // Simply "emulates" a 128 bit multiplication.
+ // However: the resulting number only contains 64 bits. The least
+ // significant 64 bits are only used for rounding the most significant 64
+ // bits.
+ const uint64_t kM32 = 0xFFFFFFFFU;
+ uint64_t a = f_ >> 32;
+ uint64_t b = f_ & kM32;
+ uint64_t c = other.f_ >> 32;
+ uint64_t d = other.f_ & kM32;
+ uint64_t ac = a * c;
+ uint64_t bc = b * c;
+ uint64_t ad = a * d;
+ uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);
+ // By adding 1U << 31 to tmp we round the final result.
+ // Halfway cases will be round up.
+ tmp += 1U << 31;
+ uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
+ e_ += other.e_ + 64;
+ f_ = result_f;
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/diy-fp.h b/Source/JavaScriptCore/wtf/dtoa/diy-fp.h
new file mode 100644
index 000000000..e843100a8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/diy-fp.h
@@ -0,0 +1,122 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_DIY_FP_H_
+#define DOUBLE_CONVERSION_DIY_FP_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // This "Do It Yourself Floating Point" class implements a floating-point number
+ // with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+ // have the most significant bit of the significand set.
+ // Multiplication and Subtraction do not normalize their results.
+ // DiyFp are not designed to contain special doubles (NaN and Infinity).
+ class DiyFp {
+ public:
+ static const int kSignificandSize = 64;
+
+ DiyFp() : f_(0), e_(0) {}
+ DiyFp(uint64_t f, int e) : f_(f), e_(e) {}
+
+ // this = this - other.
+ // The exponents of both numbers must be the same and the significand of this
+ // must be bigger than the significand of other.
+ // The result will not be normalized.
+ void Subtract(const DiyFp& other) {
+ ASSERT(e_ == other.e_);
+ ASSERT(f_ >= other.f_);
+ f_ -= other.f_;
+ }
+
+ // Returns a - b.
+ // The exponents of both numbers must be the same and this must be bigger
+ // than other. The result will not be normalized.
+ static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
+ DiyFp result = a;
+ result.Subtract(b);
+ return result;
+ }
+
+
+ // this = this * other.
+ void Multiply(const DiyFp& other);
+
+ // returns a * b;
+ static DiyFp Times(const DiyFp& a, const DiyFp& b) {
+ DiyFp result = a;
+ result.Multiply(b);
+ return result;
+ }
+
+ void Normalize() {
+ ASSERT(f_ != 0);
+ uint64_t f = f_;
+ int e = e_;
+
+ // This method is mainly called for normalizing boundaries. In general
+ // boundaries need to be shifted by 10 bits. We thus optimize for this case.
+ const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000);
+ while ((f & k10MSBits) == 0) {
+ f <<= 10;
+ e -= 10;
+ }
+ while ((f & kUint64MSB) == 0) {
+ f <<= 1;
+ e--;
+ }
+ f_ = f;
+ e_ = e;
+ }
+
+ static DiyFp Normalize(const DiyFp& a) {
+ DiyFp result = a;
+ result.Normalize();
+ return result;
+ }
+
+ uint64_t f() const { return f_; }
+ int e() const { return e_; }
+
+ void set_f(uint64_t new_value) { f_ = new_value; }
+ void set_e(int new_value) { e_ = new_value; }
+
+ private:
+ static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000);
+
+ uint64_t f_;
+ int e_;
+ };
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_DIY_FP_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/double-conversion.cc b/Source/JavaScriptCore/wtf/dtoa/double-conversion.cc
new file mode 100644
index 000000000..cab1a51f2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/double-conversion.cc
@@ -0,0 +1,870 @@
+// Copyright 2010 the V8 project authors. 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 <limits.h>
+#include <math.h>
+
+#include "double-conversion.h"
+
+#include "bignum-dtoa.h"
+#include "double.h"
+#include "fast-dtoa.h"
+#include "fixed-dtoa.h"
+#include "strtod.h"
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
+ int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
+ static DoubleToStringConverter converter(flags,
+ "Infinity",
+ "NaN",
+ 'e',
+ -6, 21,
+ 6, 0);
+ return converter;
+ }
+
+
+ bool DoubleToStringConverter::HandleSpecialValues(
+ double value,
+ StringBuilder* result_builder) const {
+ Double double_inspect(value);
+ if (double_inspect.IsInfinite()) {
+ if (infinity_symbol_ == NULL) return false;
+ if (value < 0) {
+ result_builder->AddCharacter('-');
+ }
+ result_builder->AddString(infinity_symbol_);
+ return true;
+ }
+ if (double_inspect.IsNan()) {
+ if (nan_symbol_ == NULL) return false;
+ result_builder->AddString(nan_symbol_);
+ return true;
+ }
+ return false;
+ }
+
+
+ void DoubleToStringConverter::CreateExponentialRepresentation(
+ const char* decimal_digits,
+ int length,
+ int exponent,
+ StringBuilder* result_builder) const {
+ ASSERT(length != 0);
+ result_builder->AddCharacter(decimal_digits[0]);
+ if (length != 1) {
+ result_builder->AddCharacter('.');
+ result_builder->AddSubstring(&decimal_digits[1], length-1);
+ }
+ result_builder->AddCharacter(exponent_character_);
+ if (exponent < 0) {
+ result_builder->AddCharacter('-');
+ exponent = -exponent;
+ } else {
+ if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
+ result_builder->AddCharacter('+');
+ }
+ }
+ if (exponent == 0) {
+ result_builder->AddCharacter('0');
+ return;
+ }
+ ASSERT(exponent < 1e4);
+ const int kMaxExponentLength = 5;
+ char buffer[kMaxExponentLength];
+ int first_char_pos = kMaxExponentLength;
+ while (exponent > 0) {
+ buffer[--first_char_pos] = '0' + (exponent % 10);
+ exponent /= 10;
+ }
+ result_builder->AddSubstring(&buffer[first_char_pos],
+ kMaxExponentLength - first_char_pos);
+ }
+
+
+ void DoubleToStringConverter::CreateDecimalRepresentation(
+ const char* decimal_digits,
+ int length,
+ int decimal_point,
+ int digits_after_point,
+ StringBuilder* result_builder) const {
+ // Create a representation that is padded with zeros if needed.
+ if (decimal_point <= 0) {
+ // "0.00000decimal_rep".
+ result_builder->AddCharacter('0');
+ if (digits_after_point > 0) {
+ result_builder->AddCharacter('.');
+ result_builder->AddPadding('0', -decimal_point);
+ ASSERT(length <= digits_after_point - (-decimal_point));
+ result_builder->AddSubstring(decimal_digits, length);
+ int remaining_digits = digits_after_point - (-decimal_point) - length;
+ result_builder->AddPadding('0', remaining_digits);
+ }
+ } else if (decimal_point >= length) {
+ // "decimal_rep0000.00000" or "decimal_rep.0000"
+ result_builder->AddSubstring(decimal_digits, length);
+ result_builder->AddPadding('0', decimal_point - length);
+ if (digits_after_point > 0) {
+ result_builder->AddCharacter('.');
+ result_builder->AddPadding('0', digits_after_point);
+ }
+ } else {
+ // "decima.l_rep000"
+ ASSERT(digits_after_point > 0);
+ result_builder->AddSubstring(decimal_digits, decimal_point);
+ result_builder->AddCharacter('.');
+ ASSERT(length - decimal_point <= digits_after_point);
+ result_builder->AddSubstring(&decimal_digits[decimal_point],
+ length - decimal_point);
+ int remaining_digits = digits_after_point - (length - decimal_point);
+ result_builder->AddPadding('0', remaining_digits);
+ }
+ if (digits_after_point == 0) {
+ if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
+ result_builder->AddCharacter('.');
+ }
+ if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
+ result_builder->AddCharacter('0');
+ }
+ }
+ }
+
+
+ bool DoubleToStringConverter::ToShortest(double value,
+ StringBuilder* result_builder) const {
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ int decimal_point;
+ bool sign;
+ const int kDecimalRepCapacity = kBase10MaximalLength + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+
+ DoubleToAscii(value, SHORTEST, 0, decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+
+ bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ int exponent = decimal_point - 1;
+ if ((decimal_in_shortest_low_ <= exponent) &&
+ (exponent < decimal_in_shortest_high_)) {
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
+ decimal_point,
+ Max(0, decimal_rep_length - decimal_point),
+ result_builder);
+ } else {
+ CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
+ result_builder);
+ }
+ return true;
+ }
+
+
+ bool DoubleToStringConverter::ToFixed(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const {
+ ASSERT(kMaxFixedDigitsBeforePoint == 60);
+ const double kFirstNonFixed = 1e60;
+
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
+ if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
+
+ // Find a sufficiently precise decimal representation of n.
+ int decimal_point;
+ bool sign;
+ // Add space for the '\0' byte.
+ const int kDecimalRepCapacity =
+ kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+ DoubleToAscii(value, FIXED, requested_digits,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+ requested_digits, result_builder);
+ return true;
+ }
+
+
+ bool DoubleToStringConverter::ToExponential(
+ double value,
+ int requested_digits,
+ StringBuilder* result_builder) const {
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (requested_digits < -1) return false;
+ if (requested_digits > kMaxExponentialDigits) return false;
+
+ int decimal_point;
+ bool sign;
+ // Add space for digit before the decimal point and the '\0' character.
+ const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
+ ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+
+ if (requested_digits == -1) {
+ DoubleToAscii(value, SHORTEST, 0,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ } else {
+ DoubleToAscii(value, PRECISION, requested_digits + 1,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ ASSERT(decimal_rep_length <= requested_digits + 1);
+
+ for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
+ decimal_rep[i] = '0';
+ }
+ decimal_rep_length = requested_digits + 1;
+ }
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ int exponent = decimal_point - 1;
+ CreateExponentialRepresentation(decimal_rep,
+ decimal_rep_length,
+ exponent,
+ result_builder);
+ return true;
+ }
+
+
+ bool DoubleToStringConverter::ToPrecision(double value,
+ int precision,
+ StringBuilder* result_builder) const {
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
+ return false;
+ }
+
+ // Find a sufficiently precise decimal representation of n.
+ int decimal_point;
+ bool sign;
+ // Add one for the terminating null character.
+ const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+
+ DoubleToAscii(value, PRECISION, precision,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ ASSERT(decimal_rep_length <= precision);
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ // The exponent if we print the number as x.xxeyyy. That is with the
+ // decimal point after the first digit.
+ int exponent = decimal_point - 1;
+
+ int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
+ if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
+ (decimal_point - precision + extra_zero >
+ max_trailing_padding_zeroes_in_precision_mode_)) {
+ // Fill buffer to contain 'precision' digits.
+ // Usually the buffer is already at the correct length, but 'DoubleToAscii'
+ // is allowed to return less characters.
+ for (int i = decimal_rep_length; i < precision; ++i) {
+ decimal_rep[i] = '0';
+ }
+
+ CreateExponentialRepresentation(decimal_rep,
+ precision,
+ exponent,
+ result_builder);
+ } else {
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+ Max(0, precision - decimal_point),
+ result_builder);
+ }
+ return true;
+ }
+
+
+ static BignumDtoaMode DtoaToBignumDtoaMode(
+ DoubleToStringConverter::DtoaMode dtoa_mode) {
+ switch (dtoa_mode) {
+ case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
+ case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
+ case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
+ default:
+ UNREACHABLE();
+ return BIGNUM_DTOA_SHORTEST; // To silence compiler.
+ }
+ }
+
+
+ void DoubleToStringConverter::DoubleToAscii(double v,
+ DtoaMode mode,
+ int requested_digits,
+ char* buffer,
+ int buffer_length,
+ bool* sign,
+ int* length,
+ int* point) {
+ Vector<char> vector(buffer, buffer_length);
+ ASSERT(!Double(v).IsSpecial());
+ ASSERT(mode == SHORTEST || requested_digits >= 0);
+
+ if (Double(v).Sign() < 0) {
+ *sign = true;
+ v = -v;
+ } else {
+ *sign = false;
+ }
+
+ if (mode == PRECISION && requested_digits == 0) {
+ vector[0] = '\0';
+ *length = 0;
+ return;
+ }
+
+ if (v == 0) {
+ vector[0] = '0';
+ vector[1] = '\0';
+ *length = 1;
+ *point = 1;
+ return;
+ }
+
+ bool fast_worked;
+ switch (mode) {
+ case SHORTEST:
+ fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
+ break;
+ case FIXED:
+ fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
+ break;
+ case PRECISION:
+ fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
+ vector, length, point);
+ break;
+ default:
+ UNREACHABLE();
+ fast_worked = false;
+ }
+ if (fast_worked) return;
+
+ // If the fast dtoa didn't succeed use the slower bignum version.
+ BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
+ BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
+ vector[*length] = '\0';
+ }
+
+
+ // Consumes the given substring from the iterator.
+ // Returns false, if the substring does not match.
+ static bool ConsumeSubString(const char** current,
+ const char* end,
+ const char* substring) {
+ ASSERT(**current == *substring);
+ for (substring++; *substring != '\0'; substring++) {
+ ++*current;
+ if (*current == end || **current != *substring) return false;
+ }
+ ++*current;
+ return true;
+ }
+
+
+ // Maximum number of significant digits in decimal representation.
+ // The longest possible double in decimal representation is
+ // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+ // (768 digits). If we parse a number whose first digits are equal to a
+ // mean of 2 adjacent doubles (that could have up to 769 digits) the result
+ // must be rounded to the bigger one unless the tail consists of zeros, so
+ // we don't need to preserve all the digits.
+ const int kMaxSignificantDigits = 772;
+
+
+ // Returns true if a nonspace found and false if the end has reached.
+ static inline bool AdvanceToNonspace(const char** current, const char* end) {
+ while (*current != end) {
+ if (**current != ' ') return true;
+ ++*current;
+ }
+ return false;
+ }
+
+
+ static bool isDigit(int x, int radix) {
+ return (x >= '0' && x <= '9' && x < '0' + radix)
+ || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
+ || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
+ }
+
+
+ static double SignedZero(bool sign) {
+ return sign ? -0.0 : 0.0;
+ }
+
+
+ // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
+ template <int radix_log_2>
+ static double RadixStringToDouble(const char* current,
+ const char* end,
+ bool sign,
+ bool allow_trailing_junk,
+ double junk_string_value,
+ const char** trailing_pointer) {
+ ASSERT(current != end);
+
+ // Skip leading 0s.
+ while (*current == '0') {
+ ++current;
+ if (current == end) {
+ *trailing_pointer = end;
+ return SignedZero(sign);
+ }
+ }
+
+ int64_t number = 0;
+ int exponent = 0;
+ const int radix = (1 << radix_log_2);
+
+ do {
+ int digit;
+ if (*current >= '0' && *current <= '9' && *current < '0' + radix) {
+ digit = static_cast<char>(*current) - '0';
+ } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) {
+ digit = static_cast<char>(*current) - 'a' + 10;
+ } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {
+ digit = static_cast<char>(*current) - 'A' + 10;
+ } else {
+ if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) {
+ break;
+ } else {
+ return junk_string_value;
+ }
+ }
+
+ number = number * radix + digit;
+ int overflow = static_cast<int>(number >> 53);
+ if (overflow != 0) {
+ // Overflow occurred. Need to determine which direction to round the
+ // result.
+ int overflow_bits_count = 1;
+ while (overflow > 1) {
+ overflow_bits_count++;
+ overflow >>= 1;
+ }
+
+ int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
+ int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
+ number >>= overflow_bits_count;
+ exponent = overflow_bits_count;
+
+ bool zero_tail = true;
+ while (true) {
+ ++current;
+ if (current == end || !isDigit(*current, radix)) break;
+ zero_tail = zero_tail && *current == '0';
+ exponent += radix_log_2;
+ }
+
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value;
+ }
+
+ int middle_value = (1 << (overflow_bits_count - 1));
+ if (dropped_bits > middle_value) {
+ number++; // Rounding up.
+ } else if (dropped_bits == middle_value) {
+ // Rounding to even to consistency with decimals: half-way case rounds
+ // up if significant part is odd and down otherwise.
+ if ((number & 1) != 0 || !zero_tail) {
+ number++; // Rounding up.
+ }
+ }
+
+ // Rounding up may cause overflow.
+ if ((number & ((int64_t)1 << 53)) != 0) {
+ exponent++;
+ number >>= 1;
+ }
+ break;
+ }
+ ++current;
+ } while (current != end);
+
+ ASSERT(number < ((int64_t)1 << 53));
+ ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
+
+ *trailing_pointer = current;
+
+ if (exponent == 0) {
+ if (sign) {
+ if (number == 0) return -0.0;
+ number = -number;
+ }
+ return static_cast<double>(number);
+ }
+
+ ASSERT(number != 0);
+ return Double(DiyFp(number, exponent)).value();
+ }
+
+
+ double StringToDoubleConverter::StringToDouble(
+ const char* input,
+ int length,
+ int* processed_characters_count) {
+ const char* current = input;
+ const char* end = input + length;
+
+ *processed_characters_count = 0;
+
+ const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
+ const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
+ const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
+ const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
+
+ // To make sure that iterator dereferencing is valid the following
+ // convention is used:
+ // 1. Each '++current' statement is followed by check for equality to 'end'.
+ // 2. If AdvanceToNonspace returned false then current == end.
+ // 3. If 'current' becomes equal to 'end' the function returns or goes to
+ // 'parsing_done'.
+ // 4. 'current' is not dereferenced after the 'parsing_done' label.
+ // 5. Code before 'parsing_done' may rely on 'current != end'.
+ if (current == end) return empty_string_value_;
+
+ if (allow_leading_spaces || allow_trailing_spaces) {
+ if (!AdvanceToNonspace(&current, end)) {
+ *processed_characters_count = current - input;
+ return empty_string_value_;
+ }
+ if (!allow_leading_spaces && (input != current)) {
+ // No leading spaces allowed, but AdvanceToNonspace moved forward.
+ return junk_string_value_;
+ }
+ }
+
+ // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
+ const int kBufferSize = kMaxSignificantDigits + 10;
+ char buffer[kBufferSize]; // NOLINT: size is known at compile time.
+ int buffer_pos = 0;
+
+ // Exponent will be adjusted if insignificant digits of the integer part
+ // or insignificant leading zeros of the fractional part are dropped.
+ int exponent = 0;
+ int significant_digits = 0;
+ int insignificant_digits = 0;
+ bool nonzero_digit_dropped = false;
+ bool sign = false;
+
+ if (*current == '+' || *current == '-') {
+ sign = (*current == '-');
+ ++current;
+ const char* next_non_space = current;
+ // Skip following spaces (if allowed).
+ if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
+ if (!allow_spaces_after_sign && (current != next_non_space)) {
+ return junk_string_value_;
+ }
+ current = next_non_space;
+ }
+
+ if (infinity_symbol_ != NULL) {
+ if (*current == infinity_symbol_[0]) {
+ if (!ConsumeSubString(&current, end, infinity_symbol_)) {
+ return junk_string_value_;
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+
+ ASSERT(buffer_pos == 0);
+ *processed_characters_count = current - input;
+ return sign ? -Double::Infinity() : Double::Infinity();
+ }
+ }
+
+ if (nan_symbol_ != NULL) {
+ if (*current == nan_symbol_[0]) {
+ if (!ConsumeSubString(&current, end, nan_symbol_)) {
+ return junk_string_value_;
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+
+ ASSERT(buffer_pos == 0);
+ *processed_characters_count = current - input;
+ return sign ? -Double::NaN() : Double::NaN();
+ }
+ }
+
+ bool leading_zero = false;
+ if (*current == '0') {
+ ++current;
+ if (current == end) {
+ *processed_characters_count = current - input;
+ return SignedZero(sign);
+ }
+
+ leading_zero = true;
+
+ // It could be hexadecimal value.
+ if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
+ ++current;
+ if (current == end || !isDigit(*current, 16)) {
+ return junk_string_value_; // "0x".
+ }
+
+ const char* tail_pointer = NULL;
+ double result = RadixStringToDouble<4>(current,
+ end,
+ sign,
+ allow_trailing_junk,
+ junk_string_value_,
+ &tail_pointer);
+ if (tail_pointer != NULL) {
+ if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);
+ *processed_characters_count = tail_pointer - input;
+ }
+ return result;
+ }
+
+ // Ignore leading zeros in the integer part.
+ while (*current == '0') {
+ ++current;
+ if (current == end) {
+ *processed_characters_count = current - input;
+ return SignedZero(sign);
+ }
+ }
+ }
+
+ bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
+
+ // Copy significant digits of the integer part (if any) to the buffer.
+ while (*current >= '0' && *current <= '9') {
+ if (significant_digits < kMaxSignificantDigits) {
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(*current);
+ significant_digits++;
+ // Will later check if it's an octal in the buffer.
+ } else {
+ insignificant_digits++; // Move the digit into the exponential part.
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+ }
+ octal = octal && *current < '8';
+ ++current;
+ if (current == end) goto parsing_done;
+ }
+
+ if (significant_digits == 0) {
+ octal = false;
+ }
+
+ if (*current == '.') {
+ if (octal && !allow_trailing_junk) return junk_string_value_;
+ if (octal) goto parsing_done;
+
+ ++current;
+ if (current == end) {
+ if (significant_digits == 0 && !leading_zero) {
+ return junk_string_value_;
+ } else {
+ goto parsing_done;
+ }
+ }
+
+ if (significant_digits == 0) {
+ // octal = false;
+ // Integer part consists of 0 or is absent. Significant digits start after
+ // leading zeros (if any).
+ while (*current == '0') {
+ ++current;
+ if (current == end) {
+ *processed_characters_count = current - input;
+ return SignedZero(sign);
+ }
+ exponent--; // Move this 0 into the exponent.
+ }
+ }
+
+ // There is a fractional part.
+ while (*current >= '0' && *current <= '9') {
+ if (significant_digits < kMaxSignificantDigits) {
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(*current);
+ significant_digits++;
+ exponent--;
+ } else {
+ // Ignore insignificant digits in the fractional part.
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+ }
+ ++current;
+ if (current == end) goto parsing_done;
+ }
+ }
+
+ if (!leading_zero && exponent == 0 && significant_digits == 0) {
+ // If leading_zeros is true then the string contains zeros.
+ // If exponent < 0 then string was [+-]\.0*...
+ // If significant_digits != 0 the string is not equal to 0.
+ // Otherwise there are no digits in the string.
+ return junk_string_value_;
+ }
+
+ // Parse exponential part.
+ if (*current == 'e' || *current == 'E') {
+ if (octal && !allow_trailing_junk) return junk_string_value_;
+ if (octal) goto parsing_done;
+ ++current;
+ if (current == end) {
+ if (allow_trailing_junk) {
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+ char sign = '+';
+ if (*current == '+' || *current == '-') {
+ sign = static_cast<char>(*current);
+ ++current;
+ if (current == end) {
+ if (allow_trailing_junk) {
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+ }
+
+ if (current == end || *current < '0' || *current > '9') {
+ if (allow_trailing_junk) {
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+
+ const int max_exponent = INT_MAX / 2;
+ ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
+ int num = 0;
+ do {
+ // Check overflow.
+ int digit = *current - '0';
+ if (num >= max_exponent / 10
+ && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
+ num = max_exponent;
+ } else {
+ num = num * 10 + digit;
+ }
+ ++current;
+ } while (current != end && *current >= '0' && *current <= '9');
+
+ exponent += (sign == '-' ? -num : num);
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+ if (allow_trailing_spaces) {
+ AdvanceToNonspace(&current, end);
+ }
+
+ parsing_done:
+ exponent += insignificant_digits;
+
+ if (octal) {
+ double result;
+ const char* tail_pointer = NULL;
+ result = RadixStringToDouble<3>(buffer,
+ buffer + buffer_pos,
+ sign,
+ allow_trailing_junk,
+ junk_string_value_,
+ &tail_pointer);
+ ASSERT(tail_pointer != NULL);
+ *processed_characters_count = current - input;
+ return result;
+ }
+
+ if (nonzero_digit_dropped) {
+ buffer[buffer_pos++] = '1';
+ exponent--;
+ }
+
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos] = '\0';
+
+ double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+ *processed_characters_count = current - input;
+ return sign? -converted: converted;
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/double-conversion.h b/Source/JavaScriptCore/wtf/dtoa/double-conversion.h
new file mode 100644
index 000000000..4d6fc2f57
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/double-conversion.h
@@ -0,0 +1,502 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ class DoubleToStringConverter {
+ public:
+ // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
+ // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
+ // function returns false.
+ static const int kMaxFixedDigitsBeforePoint = 60;
+ static const int kMaxFixedDigitsAfterPoint = 60;
+
+ // When calling ToExponential with a requested_digits
+ // parameter > kMaxExponentialDigits then the function returns false.
+ static const int kMaxExponentialDigits = 120;
+
+ // When calling ToPrecision with a requested_digits
+ // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
+ // then the function returns false.
+ static const int kMinPrecisionDigits = 1;
+ static const int kMaxPrecisionDigits = 120;
+
+ enum Flags {
+ NO_FLAGS = 0,
+ EMIT_POSITIVE_EXPONENT_SIGN = 1,
+ EMIT_TRAILING_DECIMAL_POINT = 2,
+ EMIT_TRAILING_ZERO_AFTER_POINT = 4,
+ UNIQUE_ZERO = 8
+ };
+
+ // Flags should be a bit-or combination of the possible Flags-enum.
+ // - NO_FLAGS: no special flags.
+ // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
+ // form, emits a '+' for positive exponents. Example: 1.2e+2.
+ // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
+ // converted into decimal format then a trailing decimal point is appended.
+ // Example: 2345.0 is converted to "2345.".
+ // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
+ // emits a trailing '0'-character. This flag requires the
+ // EXMIT_TRAILING_DECIMAL_POINT flag.
+ // Example: 2345.0 is converted to "2345.0".
+ // - UNIQUE_ZERO: "-0.0" is converted to "0.0".
+ //
+ // Infinity symbol and nan_symbol provide the string representation for these
+ // special values. If the string is NULL and the special value is encountered
+ // then the conversion functions return false.
+ //
+ // The exponent_character is used in exponential representations. It is
+ // usually 'e' or 'E'.
+ //
+ // When converting to the shortest representation the converter will
+ // represent input numbers in decimal format if they are in the interval
+ // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
+ // (lower boundary included, greater boundary excluded).
+ // Example: with decimal_in_shortest_low = -6 and
+ // decimal_in_shortest_high = 21:
+ // ToShortest(0.000001) -> "0.000001"
+ // ToShortest(0.0000001) -> "1e-7"
+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"
+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"
+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+ //
+ // When converting to precision mode the converter may add
+ // max_leading_padding_zeroes before returning the number in exponential
+ // format.
+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+ // ToPrecision(0.0000012345, 2) -> "0.0000012"
+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"
+ // Similarily the converter may add up to
+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+ // returning an exponential representation. A zero added by the
+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+ // ToPrecision(230.0, 2) -> "230"
+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+ DoubleToStringConverter(int flags,
+ const char* infinity_symbol,
+ const char* nan_symbol,
+ char exponent_character,
+ int decimal_in_shortest_low,
+ int decimal_in_shortest_high,
+ int max_leading_padding_zeroes_in_precision_mode,
+ int max_trailing_padding_zeroes_in_precision_mode)
+ : flags_(flags),
+ infinity_symbol_(infinity_symbol),
+ nan_symbol_(nan_symbol),
+ exponent_character_(exponent_character),
+ decimal_in_shortest_low_(decimal_in_shortest_low),
+ decimal_in_shortest_high_(decimal_in_shortest_high),
+ max_leading_padding_zeroes_in_precision_mode_(
+ max_leading_padding_zeroes_in_precision_mode),
+ max_trailing_padding_zeroes_in_precision_mode_(
+ max_trailing_padding_zeroes_in_precision_mode) {
+ // When 'trailing zero after the point' is set, then 'trailing point'
+ // must be set too.
+ ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
+ !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
+ }
+
+ // Returns a converter following the EcmaScript specification.
+ static const DoubleToStringConverter& EcmaScriptConverter();
+
+ // Computes the shortest string of digits that correctly represent the input
+ // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
+ // (see constructor) it then either returns a decimal representation, or an
+ // exponential representation.
+ // Example with decimal_in_shortest_low = -6,
+ // decimal_in_shortest_high = 21,
+ // EMIT_POSITIVE_EXPONENT_SIGN activated, and
+ // EMIT_TRAILING_DECIMAL_POINT deactived:
+ // ToShortest(0.000001) -> "0.000001"
+ // ToShortest(0.0000001) -> "1e-7"
+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"
+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"
+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+ //
+ // Note: the conversion may round the output if the returned string
+ // is accurate enough to uniquely identify the input-number.
+ // For example the most precise representation of the double 9e59 equals
+ // "899999999999999918767229449717619953810131273674690656206848", but
+ // the converter will return the shorter (but still correct) "9e59".
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except when the input value is special and no infinity_symbol or
+ // nan_symbol has been given to the constructor.
+ bool ToShortest(double value, StringBuilder* result_builder) const;
+
+
+ // Computes a decimal representation with a fixed number of digits after the
+ // decimal point. The last emitted digit is rounded.
+ //
+ // Examples:
+ // ToFixed(3.12, 1) -> "3.1"
+ // ToFixed(3.1415, 3) -> "3.142"
+ // ToFixed(1234.56789, 4) -> "1234.5679"
+ // ToFixed(1.23, 5) -> "1.23000"
+ // ToFixed(0.1, 4) -> "0.1000"
+ // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
+ // ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
+ // ToFixed(0.1, 17) -> "0.10000000000000001"
+ //
+ // If requested_digits equals 0, then the tail of the result depends on
+ // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
+ // Examples, for requested_digits == 0,
+ // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
+ // - false and false: then 123.45 -> 123
+ // 0.678 -> 1
+ // - true and false: then 123.45 -> 123.
+ // 0.678 -> 1.
+ // - true and true: then 123.45 -> 123.0
+ // 0.678 -> 1.0
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - 'value' > 10^kMaxFixedDigitsBeforePoint, or
+ // - 'requested_digits' > kMaxFixedDigitsAfterPoint.
+ // The last two conditions imply that the result will never contain more than
+ // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
+ // (one additional character for the sign, and one for the decimal point).
+ bool ToFixed(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const;
+
+ // Computes a representation in exponential format with requested_digits
+ // after the decimal point. The last emitted digit is rounded.
+ // If requested_digits equals -1, then the shortest exponential representation
+ // is computed.
+ //
+ // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
+ // exponent_character set to 'e'.
+ // ToExponential(3.12, 1) -> "3.1e0"
+ // ToExponential(5.0, 3) -> "5.000e0"
+ // ToExponential(0.001, 2) -> "1.00e-3"
+ // ToExponential(3.1415, -1) -> "3.1415e0"
+ // ToExponential(3.1415, 4) -> "3.1415e0"
+ // ToExponential(3.1415, 3) -> "3.142e0"
+ // ToExponential(123456789000000, 3) -> "1.235e14"
+ // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
+ // ToExponential(1000000000000000019884624838656.0, 32) ->
+ // "1.00000000000000001988462483865600e30"
+ // ToExponential(1234, 0) -> "1e3"
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - 'requested_digits' > kMaxExponentialDigits.
+ // The last condition implies that the result will never contain more than
+ // kMaxExponentialDigits + 8 characters (the sign, the digit before the
+ // decimal point, the decimal point, the exponent character, the
+ // exponent's sign, and at most 3 exponent digits).
+ bool ToExponential(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const;
+
+ // Computes 'precision' leading digits of the given 'value' and returns them
+ // either in exponential or decimal format, depending on
+ // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
+ // constructor).
+ // The last computed digit is rounded.
+ //
+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+ // ToPrecision(0.0000012345, 2) -> "0.0000012"
+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"
+ // Similarily the converter may add up to
+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+ // returning an exponential representation. A zero added by the
+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+ // ToPrecision(230.0, 2) -> "230"
+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
+ // EMIT_TRAILING_ZERO_AFTER_POINT:
+ // ToPrecision(123450.0, 6) -> "123450"
+ // ToPrecision(123450.0, 5) -> "123450"
+ // ToPrecision(123450.0, 4) -> "123500"
+ // ToPrecision(123450.0, 3) -> "123000"
+ // ToPrecision(123450.0, 2) -> "1.2e5"
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - precision < kMinPericisionDigits
+ // - precision > kMaxPrecisionDigits
+ // The last condition implies that the result will never contain more than
+ // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
+ // exponent character, the exponent's sign, and at most 3 exponent digits).
+ bool ToPrecision(double value,
+ int precision,
+ StringBuilder* result_builder) const;
+
+ enum DtoaMode {
+ // Produce the shortest correct representation.
+ // For example the output of 0.299999999999999988897 is (the less accurate
+ // but correct) 0.3.
+ SHORTEST,
+ // Produce a fixed number of digits after the decimal point.
+ // For instance fixed(0.1, 4) becomes 0.1000
+ // If the input number is big, the output will be big.
+ FIXED,
+ // Fixed number of digits (independent of the decimal point).
+ PRECISION
+ };
+
+ // The maximal number of digits that are needed to emit a double in base 10.
+ // A higher precision can be achieved by using more digits, but the shortest
+ // accurate representation of any double will never use more digits than
+ // kBase10MaximalLength.
+ // Note that DoubleToAscii null-terminates its input. So the given buffer
+ // should be at least kBase10MaximalLength + 1 characters long.
+ static const int kBase10MaximalLength = 17;
+
+ // Converts the given double 'v' to ascii.
+ // The result should be interpreted as buffer * 10^(point-length).
+ //
+ // The output depends on the given mode:
+ // - SHORTEST: produce the least amount of digits for which the internal
+ // identity requirement is still satisfied. If the digits are printed
+ // (together with the correct exponent) then reading this number will give
+ // 'v' again. The buffer will choose the representation that is closest to
+ // 'v'. If there are two at the same distance, than the one farther away
+ // from 0 is chosen (halfway cases - ending with 5 - are rounded up).
+ // In this mode the 'requested_digits' parameter is ignored.
+ // - FIXED: produces digits necessary to print a given number with
+ // 'requested_digits' digits after the decimal point. The produced digits
+ // might be too short in which case the caller has to fill the remainder
+ // with '0's.
+ // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+ // Halfway cases are rounded towards +/-Infinity (away from 0). The call
+ // toFixed(0.15, 2) thus returns buffer="2", point=0.
+ // The returned buffer may contain digits that would be truncated from the
+ // shortest representation of the input.
+ // - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+ // Even though the length of produced digits usually equals
+ // 'requested_digits', the function is allowed to return fewer digits, in
+ // which case the caller has to fill the missing digits with '0's.
+ // Halfway cases are again rounded away from 0.
+ // DoubleToAscii expects the given buffer to be big enough to hold all
+ // digits and a terminating null-character. In SHORTEST-mode it expects a
+ // buffer of at least kBase10MaximalLength + 1. In all other modes the
+ // requested_digits parameter (+ 1 for the null-character) limits the size of
+ // the output. The given length is only used in debug mode to ensure the
+ // buffer is big enough.
+ static void DoubleToAscii(double v,
+ DtoaMode mode,
+ int requested_digits,
+ char* buffer,
+ int buffer_length,
+ bool* sign,
+ int* length,
+ int* point);
+
+ private:
+ // If the value is a special value (NaN or Infinity) constructs the
+ // corresponding string using the configured infinity/nan-symbol.
+ // If either of them is NULL or the value is not special then the
+ // function returns false.
+ bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
+ // Constructs an exponential representation (i.e. 1.234e56).
+ // The given exponent assumes a decimal point after the first decimal digit.
+ void CreateExponentialRepresentation(const char* decimal_digits,
+ int length,
+ int exponent,
+ StringBuilder* result_builder) const;
+ // Creates a decimal representation (i.e 1234.5678).
+ void CreateDecimalRepresentation(const char* decimal_digits,
+ int length,
+ int decimal_point,
+ int digits_after_point,
+ StringBuilder* result_builder) const;
+
+ const int flags_;
+ const char* const infinity_symbol_;
+ const char* const nan_symbol_;
+ const char exponent_character_;
+ const int decimal_in_shortest_low_;
+ const int decimal_in_shortest_high_;
+ const int max_leading_padding_zeroes_in_precision_mode_;
+ const int max_trailing_padding_zeroes_in_precision_mode_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
+ };
+
+
+ class StringToDoubleConverter {
+ public:
+ // Enumeration for allowing octals and ignoring junk when converting
+ // strings to numbers.
+ enum Flags {
+ NO_FLAGS = 0,
+ ALLOW_HEX = 1,
+ ALLOW_OCTALS = 2,
+ ALLOW_TRAILING_JUNK = 4,
+ ALLOW_LEADING_SPACES = 8,
+ ALLOW_TRAILING_SPACES = 16,
+ ALLOW_SPACES_AFTER_SIGN = 32
+ };
+
+ // Flags should be a bit-or combination of the possible Flags-enum.
+ // - NO_FLAGS: no special flags.
+ // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
+ // Ex: StringToDouble("0x1234") -> 4660.0
+ // In StringToDouble("0x1234.56") the characters ".56" are trailing
+ // junk. The result of the call is hence dependent on
+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.
+ // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
+ // the string will not be parsed as "0" followed by junk.
+ //
+ // - ALLOW_OCTALS: recognizes the prefix "0" for octals:
+ // If a sequence of octal digits starts with '0', then the number is
+ // read as octal integer. Octal numbers may only be integers.
+ // Ex: StringToDouble("01234") -> 668.0
+ // StringToDouble("012349") -> 12349.0 // Not a sequence of octal
+ // // digits.
+ // In StringToDouble("01234.56") the characters ".56" are trailing
+ // junk. The result of the call is hence dependent on
+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.
+ // In StringToDouble("01234e56") the characters "e56" are trailing
+ // junk, too.
+ // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
+ // a double literal.
+ // - ALLOW_LEADING_SPACES: skip over leading spaces.
+ // - ALLOW_TRAILING_SPACES: ignore trailing spaces.
+ // - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign.
+ // Ex: StringToDouble("- 123.2") -> -123.2.
+ // StringToDouble("+ 123.2") -> 123.2
+ //
+ // empty_string_value is returned when an empty string is given as input.
+ // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
+ // containing only spaces is converted to the 'empty_string_value', too.
+ //
+ // junk_string_value is returned when
+ // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
+ // part of a double-literal) is found.
+ // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
+ // double literal.
+ //
+ // infinity_symbol and nan_symbol are strings that are used to detect
+ // inputs that represent infinity and NaN. They can be null, in which case
+ // they are ignored.
+ // The conversion routine first reads any possible signs. Then it compares the
+ // following character of the input-string with the first character of
+ // the infinity, and nan-symbol. If either matches, the function assumes, that
+ // a match has been found, and expects the following input characters to match
+ // the remaining characters of the special-value symbol.
+ // This means that the following restrictions apply to special-value symbols:
+ // - they must not start with signs ('+', or '-'),
+ // - they must not have the same first character.
+ // - they must not start with digits.
+ //
+ // Examples:
+ // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
+ // empty_string_value = 0.0,
+ // junk_string_value = NaN,
+ // infinity_symbol = "infinity",
+ // nan_symbol = "nan":
+ // StringToDouble("0x1234") -> 4660.0.
+ // StringToDouble("0x1234K") -> 4660.0.
+ // StringToDouble("") -> 0.0 // empty_string_value.
+ // StringToDouble(" ") -> NaN // junk_string_value.
+ // StringToDouble(" 1") -> NaN // junk_string_value.
+ // StringToDouble("0x") -> NaN // junk_string_value.
+ // StringToDouble("-123.45") -> -123.45.
+ // StringToDouble("--123.45") -> NaN // junk_string_value.
+ // StringToDouble("123e45") -> 123e45.
+ // StringToDouble("123E45") -> 123e45.
+ // StringToDouble("123e+45") -> 123e45.
+ // StringToDouble("123E-45") -> 123e-45.
+ // StringToDouble("123e") -> 123.0 // trailing junk ignored.
+ // StringToDouble("123e-") -> 123.0 // trailing junk ignored.
+ // StringToDouble("+NaN") -> NaN // NaN string literal.
+ // StringToDouble("-infinity") -> -inf. // infinity literal.
+ // StringToDouble("Infinity") -> NaN // junk_string_value.
+ //
+ // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
+ // empty_string_value = 0.0,
+ // junk_string_value = NaN,
+ // infinity_symbol = NULL,
+ // nan_symbol = NULL:
+ // StringToDouble("0x1234") -> NaN // junk_string_value.
+ // StringToDouble("01234") -> 668.0.
+ // StringToDouble("") -> 0.0 // empty_string_value.
+ // StringToDouble(" ") -> 0.0 // empty_string_value.
+ // StringToDouble(" 1") -> 1.0
+ // StringToDouble("0x") -> NaN // junk_string_value.
+ // StringToDouble("0123e45") -> NaN // junk_string_value.
+ // StringToDouble("01239E45") -> 1239e45.
+ // StringToDouble("-infinity") -> NaN // junk_string_value.
+ // StringToDouble("NaN") -> NaN // junk_string_value.
+ StringToDoubleConverter(int flags,
+ double empty_string_value,
+ double junk_string_value,
+ const char* infinity_symbol,
+ const char* nan_symbol)
+ : flags_(flags),
+ empty_string_value_(empty_string_value),
+ junk_string_value_(junk_string_value),
+ infinity_symbol_(infinity_symbol),
+ nan_symbol_(nan_symbol) {
+ }
+
+ // Performs the conversion.
+ // The output parameter 'processed_characters_count' is set to the number
+ // of characters that have been processed to read the number.
+ // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
+ // in the 'processed_characters_count'. Trailing junk is never included.
+ double StringToDouble(const char* buffer,
+ int length,
+ int* processed_characters_count);
+
+ private:
+ const int flags_;
+ const double empty_string_value_;
+ const double junk_string_value_;
+ const char* const infinity_symbol_;
+ const char* const nan_symbol_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
+ };
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/double.h b/Source/JavaScriptCore/wtf/dtoa/double.h
new file mode 100644
index 000000000..0544fdb5a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/double.h
@@ -0,0 +1,249 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_DOUBLE_H_
+#define DOUBLE_CONVERSION_DOUBLE_H_
+
+#include "diy-fp.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // We assume that doubles and uint64_t have the same endianness.
+ static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
+ static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
+
+ // Helper functions for doubles.
+ class Double {
+ public:
+ static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);
+ static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);
+ static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
+ static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
+ static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
+ static const int kSignificandSize = 53;
+
+ Double() : d64_(0) {}
+ explicit Double(double d) : d64_(double_to_uint64(d)) {}
+ explicit Double(uint64_t d64) : d64_(d64) {}
+ explicit Double(DiyFp diy_fp)
+ : d64_(DiyFpToUint64(diy_fp)) {}
+
+ // The value encoded by this Double must be greater or equal to +0.0.
+ // It must not be special (infinity, or NaN).
+ DiyFp AsDiyFp() const {
+ ASSERT(Sign() > 0);
+ ASSERT(!IsSpecial());
+ return DiyFp(Significand(), Exponent());
+ }
+
+ // The value encoded by this Double must be strictly greater than 0.
+ DiyFp AsNormalizedDiyFp() const {
+ ASSERT(value() > 0.0);
+ uint64_t f = Significand();
+ int e = Exponent();
+
+ // The current double could be a denormal.
+ while ((f & kHiddenBit) == 0) {
+ f <<= 1;
+ e--;
+ }
+ // Do the final shifts in one go.
+ f <<= DiyFp::kSignificandSize - kSignificandSize;
+ e -= DiyFp::kSignificandSize - kSignificandSize;
+ return DiyFp(f, e);
+ }
+
+ // Returns the double's bit as uint64.
+ uint64_t AsUint64() const {
+ return d64_;
+ }
+
+ // Returns the next greater double. Returns +infinity on input +infinity.
+ double NextDouble() const {
+ if (d64_ == kInfinity) return Double(kInfinity).value();
+ if (Sign() < 0 && Significand() == 0) {
+ // -0.0
+ return 0.0;
+ }
+ if (Sign() < 0) {
+ return Double(d64_ - 1).value();
+ } else {
+ return Double(d64_ + 1).value();
+ }
+ }
+
+ int Exponent() const {
+ if (IsDenormal()) return kDenormalExponent;
+
+ uint64_t d64 = AsUint64();
+ int biased_e =
+ static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
+ return biased_e - kExponentBias;
+ }
+
+ uint64_t Significand() const {
+ uint64_t d64 = AsUint64();
+ uint64_t significand = d64 & kSignificandMask;
+ if (!IsDenormal()) {
+ return significand + kHiddenBit;
+ } else {
+ return significand;
+ }
+ }
+
+ // Returns true if the double is a denormal.
+ bool IsDenormal() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kExponentMask) == 0;
+ }
+
+ // We consider denormals not to be special.
+ // Hence only Infinity and NaN are special.
+ bool IsSpecial() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kExponentMask) == kExponentMask;
+ }
+
+ bool IsNan() const {
+ uint64_t d64 = AsUint64();
+ return ((d64 & kExponentMask) == kExponentMask) &&
+ ((d64 & kSignificandMask) != 0);
+ }
+
+ bool IsInfinite() const {
+ uint64_t d64 = AsUint64();
+ return ((d64 & kExponentMask) == kExponentMask) &&
+ ((d64 & kSignificandMask) == 0);
+ }
+
+ int Sign() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kSignMask) == 0? 1: -1;
+ }
+
+ // Precondition: the value encoded by this Double must be greater or equal
+ // than +0.0.
+ DiyFp UpperBoundary() const {
+ ASSERT(Sign() > 0);
+ return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+ }
+
+ // Computes the two boundaries of this.
+ // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+ // exponent as m_plus.
+ // Precondition: the value encoded by this Double must be greater than 0.
+ void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+ ASSERT(value() > 0.0);
+ DiyFp v = this->AsDiyFp();
+ bool significand_is_zero = (v.f() == kHiddenBit);
+ DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+ DiyFp m_minus;
+ if (significand_is_zero && v.e() != kDenormalExponent) {
+ // The boundary is closer. Think of v = 1000e10 and v- = 9999e9.
+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+ // at a distance of 1e8.
+ // The only exception is for the smallest normal: the largest denormal is
+ // at the same distance as its successor.
+ // Note: denormals have the same exponent as the smallest normals.
+ m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+ } else {
+ m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+ }
+ m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+ m_minus.set_e(m_plus.e());
+ *out_m_plus = m_plus;
+ *out_m_minus = m_minus;
+ }
+
+ double value() const { return uint64_to_double(d64_); }
+
+ // Returns the significand size for a given order of magnitude.
+ // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+ // This function returns the number of significant binary digits v will have
+ // once it's encoded into a double. In almost all cases this is equal to
+ // kSignificandSize. The only exceptions are denormals. They start with
+ // leading zeroes and their effective significand-size is hence smaller.
+ static int SignificandSizeForOrderOfMagnitude(int order) {
+ if (order >= (kDenormalExponent + kSignificandSize)) {
+ return kSignificandSize;
+ }
+ if (order <= kDenormalExponent) return 0;
+ return order - kDenormalExponent;
+ }
+
+ static double Infinity() {
+ return Double(kInfinity).value();
+ }
+
+ static double NaN() {
+ return Double(kNaN).value();
+ }
+
+ private:
+ static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+ static const int kDenormalExponent = -kExponentBias + 1;
+ static const int kMaxExponent = 0x7FF - kExponentBias;
+ static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
+ static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);
+
+ const uint64_t d64_;
+
+ static uint64_t DiyFpToUint64(DiyFp diy_fp) {
+ uint64_t significand = diy_fp.f();
+ int exponent = diy_fp.e();
+ while (significand > kHiddenBit + kSignificandMask) {
+ significand >>= 1;
+ exponent++;
+ }
+ if (exponent >= kMaxExponent) {
+ return kInfinity;
+ }
+ if (exponent < kDenormalExponent) {
+ return 0;
+ }
+ while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
+ significand <<= 1;
+ exponent--;
+ }
+ uint64_t biased_exponent;
+ if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
+ biased_exponent = 0;
+ } else {
+ biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
+ }
+ return (significand & kSignificandMask) |
+ (biased_exponent << kPhysicalSignificandSize);
+ }
+ };
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_DOUBLE_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.cc b/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.cc
new file mode 100644
index 000000000..9d9872417
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.cc
@@ -0,0 +1,741 @@
+// Copyright 2010 the V8 project authors. 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 "fast-dtoa.h"
+
+#include "cached-powers.h"
+#include "diy-fp.h"
+#include "double.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // The minimal and maximal target exponent define the range of w's binary
+ // exponent, where 'w' is the result of multiplying the input by a cached power
+ // of ten.
+ //
+ // A different range might be chosen on a different platform, to optimize digit
+ // generation, but a smaller range requires more powers of ten to be cached.
+ static const int kMinimalTargetExponent = -60;
+ static const int kMaximalTargetExponent = -32;
+
+
+ // Adjusts the last digit of the generated number, and screens out generated
+ // solutions that may be inaccurate. A solution may be inaccurate if it is
+ // outside the safe interval, or if we cannot prove that it is closer to the
+ // input than a neighboring representation of the same length.
+ //
+ // Input: * buffer containing the digits of too_high / 10^kappa
+ // * the buffer's length
+ // * distance_too_high_w == (too_high - w).f() * unit
+ // * unsafe_interval == (too_high - too_low).f() * unit
+ // * rest = (too_high - buffer * 10^kappa).f() * unit
+ // * ten_kappa = 10^kappa * unit
+ // * unit = the common multiplier
+ // Output: returns true if the buffer is guaranteed to contain the closest
+ // representable number to the input.
+ // Modifies the generated digits in the buffer to approach (round towards) w.
+ static bool RoundWeed(Vector<char> buffer,
+ int length,
+ uint64_t distance_too_high_w,
+ uint64_t unsafe_interval,
+ uint64_t rest,
+ uint64_t ten_kappa,
+ uint64_t unit) {
+ uint64_t small_distance = distance_too_high_w - unit;
+ uint64_t big_distance = distance_too_high_w + unit;
+ // Let w_low = too_high - big_distance, and
+ // w_high = too_high - small_distance.
+ // Note: w_low < w < w_high
+ //
+ // The real w (* unit) must lie somewhere inside the interval
+ // ]w_low; w_high[ (often written as "(w_low; w_high)")
+
+ // Basically the buffer currently contains a number in the unsafe interval
+ // ]too_low; too_high[ with too_low < w < too_high
+ //
+ // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // ^v 1 unit ^ ^ ^ ^
+ // boundary_high --------------------- . . . .
+ // ^v 1 unit . . . .
+ // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .
+ // . . ^ . .
+ // . big_distance . . .
+ // . . . . rest
+ // small_distance . . . .
+ // v . . . .
+ // w_high - - - - - - - - - - - - - - - - - - . . . .
+ // ^v 1 unit . . . .
+ // w ---------------------------------------- . . . .
+ // ^v 1 unit v . . .
+ // w_low - - - - - - - - - - - - - - - - - - - - - . . .
+ // . . v
+ // buffer --------------------------------------------------+-------+--------
+ // . .
+ // safe_interval .
+ // v .
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
+ // ^v 1 unit .
+ // boundary_low ------------------------- unsafe_interval
+ // ^v 1 unit v
+ // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ //
+ //
+ // Note that the value of buffer could lie anywhere inside the range too_low
+ // to too_high.
+ //
+ // boundary_low, boundary_high and w are approximations of the real boundaries
+ // and v (the input number). They are guaranteed to be precise up to one unit.
+ // In fact the error is guaranteed to be strictly less than one unit.
+ //
+ // Anything that lies outside the unsafe interval is guaranteed not to round
+ // to v when read again.
+ // Anything that lies inside the safe interval is guaranteed to round to v
+ // when read again.
+ // If the number inside the buffer lies inside the unsafe interval but not
+ // inside the safe interval then we simply do not know and bail out (returning
+ // false).
+ //
+ // Similarly we have to take into account the imprecision of 'w' when finding
+ // the closest representation of 'w'. If we have two potential
+ // representations, and one is closer to both w_low and w_high, then we know
+ // it is closer to the actual value v.
+ //
+ // By generating the digits of too_high we got the largest (closest to
+ // too_high) buffer that is still in the unsafe interval. In the case where
+ // w_high < buffer < too_high we try to decrement the buffer.
+ // This way the buffer approaches (rounds towards) w.
+ // There are 3 conditions that stop the decrementation process:
+ // 1) the buffer is already below w_high
+ // 2) decrementing the buffer would make it leave the unsafe interval
+ // 3) decrementing the buffer would yield a number below w_high and farther
+ // away than the current number. In other words:
+ // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
+ // Instead of using the buffer directly we use its distance to too_high.
+ // Conceptually rest ~= too_high - buffer
+ // We need to do the following tests in this order to avoid over- and
+ // underflows.
+ ASSERT(rest <= unsafe_interval);
+ while (rest < small_distance && // Negated condition 1
+ unsafe_interval - rest >= ten_kappa && // Negated condition 2
+ (rest + ten_kappa < small_distance || // buffer{-1} > w_high
+ small_distance - rest >= rest + ten_kappa - small_distance)) {
+ buffer[length - 1]--;
+ rest += ten_kappa;
+ }
+
+ // We have approached w+ as much as possible. We now test if approaching w-
+ // would require changing the buffer. If yes, then we have two possible
+ // representations close to w, but we cannot decide which one is closer.
+ if (rest < big_distance &&
+ unsafe_interval - rest >= ten_kappa &&
+ (rest + ten_kappa < big_distance ||
+ big_distance - rest > rest + ten_kappa - big_distance)) {
+ return false;
+ }
+
+ // Weeding test.
+ // The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+ // Since too_low = too_high - unsafe_interval this is equivalent to
+ // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+ // Conceptually we have: rest ~= too_high - buffer
+ return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
+ }
+
+
+ // Rounds the buffer upwards if the result is closer to v by possibly adding
+ // 1 to the buffer. If the precision of the calculation is not sufficient to
+ // round correctly, return false.
+ // The rounding might shift the whole buffer in which case the kappa is
+ // adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
+ //
+ // If 2*rest > ten_kappa then the buffer needs to be round up.
+ // rest can have an error of +/- 1 unit. This function accounts for the
+ // imprecision and returns false, if the rounding direction cannot be
+ // unambiguously determined.
+ //
+ // Precondition: rest < ten_kappa.
+ static bool RoundWeedCounted(Vector<char> buffer,
+ int length,
+ uint64_t rest,
+ uint64_t ten_kappa,
+ uint64_t unit,
+ int* kappa) {
+ ASSERT(rest < ten_kappa);
+ // The following tests are done in a specific order to avoid overflows. They
+ // will work correctly with any uint64 values of rest < ten_kappa and unit.
+ //
+ // If the unit is too big, then we don't know which way to round. For example
+ // a unit of 50 means that the real number lies within rest +/- 50. If
+ // 10^kappa == 40 then there is no way to tell which way to round.
+ if (unit >= ten_kappa) return false;
+ // Even if unit is just half the size of 10^kappa we are already completely
+ // lost. (And after the previous test we know that the expression will not
+ // over/underflow.)
+ if (ten_kappa - unit <= unit) return false;
+ // If 2 * (rest + unit) <= 10^kappa we can safely round down.
+ if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {
+ return true;
+ }
+ // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
+ if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {
+ // Increment the last digit recursively until we find a non '9' digit.
+ buffer[length - 1]++;
+ for (int i = length - 1; i > 0; --i) {
+ if (buffer[i] != '0' + 10) break;
+ buffer[i] = '0';
+ buffer[i - 1]++;
+ }
+ // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
+ // exception of the first digit all digits are now '0'. Simply switch the
+ // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
+ // the power (the kappa) is increased.
+ if (buffer[0] == '0' + 10) {
+ buffer[0] = '1';
+ (*kappa) += 1;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ static const uint32_t kTen4 = 10000;
+ static const uint32_t kTen5 = 100000;
+ static const uint32_t kTen6 = 1000000;
+ static const uint32_t kTen7 = 10000000;
+ static const uint32_t kTen8 = 100000000;
+ static const uint32_t kTen9 = 1000000000;
+
+ // Returns the biggest power of ten that is less than or equal to the given
+ // number. We furthermore receive the maximum number of bits 'number' has.
+ // If number_bits == 0 then 0^-1 is returned
+ // The number of bits must be <= 32.
+ // Precondition: number < (1 << (number_bits + 1)).
+ static void BiggestPowerTen(uint32_t number,
+ int number_bits,
+ uint32_t* power,
+ int* exponent) {
+ ASSERT(number < (uint32_t)(1 << (number_bits + 1)));
+
+ switch (number_bits) {
+ case 32:
+ case 31:
+ case 30:
+ if (kTen9 <= number) {
+ *power = kTen9;
+ *exponent = 9;
+ break;
+ } // else fallthrough
+ case 29:
+ case 28:
+ case 27:
+ if (kTen8 <= number) {
+ *power = kTen8;
+ *exponent = 8;
+ break;
+ } // else fallthrough
+ case 26:
+ case 25:
+ case 24:
+ if (kTen7 <= number) {
+ *power = kTen7;
+ *exponent = 7;
+ break;
+ } // else fallthrough
+ case 23:
+ case 22:
+ case 21:
+ case 20:
+ if (kTen6 <= number) {
+ *power = kTen6;
+ *exponent = 6;
+ break;
+ } // else fallthrough
+ case 19:
+ case 18:
+ case 17:
+ if (kTen5 <= number) {
+ *power = kTen5;
+ *exponent = 5;
+ break;
+ } // else fallthrough
+ case 16:
+ case 15:
+ case 14:
+ if (kTen4 <= number) {
+ *power = kTen4;
+ *exponent = 4;
+ break;
+ } // else fallthrough
+ case 13:
+ case 12:
+ case 11:
+ case 10:
+ if (1000 <= number) {
+ *power = 1000;
+ *exponent = 3;
+ break;
+ } // else fallthrough
+ case 9:
+ case 8:
+ case 7:
+ if (100 <= number) {
+ *power = 100;
+ *exponent = 2;
+ break;
+ } // else fallthrough
+ case 6:
+ case 5:
+ case 4:
+ if (10 <= number) {
+ *power = 10;
+ *exponent = 1;
+ break;
+ } // else fallthrough
+ case 3:
+ case 2:
+ case 1:
+ if (1 <= number) {
+ *power = 1;
+ *exponent = 0;
+ break;
+ } // else fallthrough
+ case 0:
+ *power = 0;
+ *exponent = -1;
+ break;
+ default:
+ // Following assignments are here to silence compiler warnings.
+ *power = 0;
+ *exponent = 0;
+ UNREACHABLE();
+ }
+ }
+
+
+ // Generates the digits of input number w.
+ // w is a floating-point number (DiyFp), consisting of a significand and an
+ // exponent. Its exponent is bounded by kMinimalTargetExponent and
+ // kMaximalTargetExponent.
+ // Hence -60 <= w.e() <= -32.
+ //
+ // Returns false if it fails, in which case the generated digits in the buffer
+ // should not be used.
+ // Preconditions:
+ // * low, w and high are correct up to 1 ulp (unit in the last place). That
+ // is, their error must be less than a unit of their last digits.
+ // * low.e() == w.e() == high.e()
+ // * low < w < high, and taking into account their error: low~ <= high~
+ // * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+ // Postconditions: returns false if procedure fails.
+ // otherwise:
+ // * buffer is not null-terminated, but len contains the number of digits.
+ // * buffer contains the shortest possible decimal digit-sequence
+ // such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+ // correct values of low and high (without their error).
+ // * if more than one decimal representation gives the minimal number of
+ // decimal digits then the one closest to W (where W is the correct value
+ // of w) is chosen.
+ // Remark: this procedure takes into account the imprecision of its input
+ // numbers. If the precision is not enough to guarantee all the postconditions
+ // then false is returned. This usually happens rarely (~0.5%).
+ //
+ // Say, for the sake of example, that
+ // w.e() == -48, and w.f() == 0x1234567890abcdef
+ // w's value can be computed by w.f() * 2^w.e()
+ // We can obtain w's integral digits by simply shifting w.f() by -w.e().
+ // -> w's integral part is 0x1234
+ // w's fractional part is therefore 0x567890abcdef.
+ // Printing w's integral part is easy (simply print 0x1234 in decimal).
+ // In order to print its fraction we repeatedly multiply the fraction by 10 and
+ // get each digit. Example the first digit after the point would be computed by
+ // (0x567890abcdef * 10) >> 48. -> 3
+ // The whole thing becomes slightly more complicated because we want to stop
+ // once we have enough digits. That is, once the digits inside the buffer
+ // represent 'w' we can stop. Everything inside the interval low - high
+ // represents w. However we have to pay attention to low, high and w's
+ // imprecision.
+ static bool DigitGen(DiyFp low,
+ DiyFp w,
+ DiyFp high,
+ Vector<char> buffer,
+ int* length,
+ int* kappa) {
+ ASSERT(low.e() == w.e() && w.e() == high.e());
+ ASSERT(low.f() + 1 <= high.f() - 1);
+ ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+ // low, w and high are imprecise, but by less than one ulp (unit in the last
+ // place).
+ // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+ // the new numbers are outside of the interval we want the final
+ // representation to lie in.
+ // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+ // numbers that are certain to lie in the interval. We will use this fact
+ // later on.
+ // We will now start by generating the digits within the uncertain
+ // interval. Later we will weed out representations that lie outside the safe
+ // interval and thus _might_ lie outside the correct interval.
+ uint64_t unit = 1;
+ DiyFp too_low = DiyFp(low.f() - unit, low.e());
+ DiyFp too_high = DiyFp(high.f() + unit, high.e());
+ // too_low and too_high are guaranteed to lie outside the interval we want the
+ // generated number in.
+ DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
+ // We now cut the input number into two parts: the integral digits and the
+ // fractionals. We will not write any decimal separator though, but adapt
+ // kappa instead.
+ // Reminder: we are currently computing the digits (stored inside the buffer)
+ // such that: too_low < buffer * 10^kappa < too_high
+ // We use too_high for the digit_generation and stop as soon as possible.
+ // If we stop early we effectively round down.
+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+ // Division by one is a shift.
+ uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
+ // Modulo by one is an and.
+ uint64_t fractionals = too_high.f() & (one.f() - 1);
+ uint32_t divisor;
+ int divisor_exponent;
+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+ &divisor, &divisor_exponent);
+ *kappa = divisor_exponent + 1;
+ *length = 0;
+ // Loop invariant: buffer = too_high / 10^kappa (integer division)
+ // The invariant holds for the first iteration: kappa has been initialized
+ // with the divisor exponent + 1. And the divisor is the biggest power of ten
+ // that is smaller than integrals.
+ while (*kappa > 0) {
+ int digit = integrals / divisor;
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ integrals %= divisor;
+ (*kappa)--;
+ // Note that kappa now equals the exponent of the divisor and that the
+ // invariant thus holds again.
+ uint64_t rest =
+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+ // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+ // Reminder: unsafe_interval.e() == one.e()
+ if (rest < unsafe_interval.f()) {
+ // Rounding down (by not emitting the remaining digits) yields a number
+ // that lies within the unsafe interval.
+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
+ unsafe_interval.f(), rest,
+ static_cast<uint64_t>(divisor) << -one.e(), unit);
+ }
+ divisor /= 10;
+ }
+
+ // The integrals have been generated. We are at the point of the decimal
+ // separator. In the following loop we simply multiply the remaining digits by
+ // 10 and divide by one. We just need to pay attention to multiply associated
+ // data (like the interval or 'unit'), too.
+ // Note that the multiplication by 10 does not overflow, because w.e >= -60
+ // and thus one.e >= -60.
+ ASSERT(one.e() >= -60);
+ ASSERT(fractionals < one.f());
+ ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+ while (true) {
+ fractionals *= 10;
+ unit *= 10;
+ unsafe_interval.set_f(unsafe_interval.f() * 10);
+ // Integer division by one.
+ int digit = static_cast<int>(fractionals >> -one.e());
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ fractionals &= one.f() - 1; // Modulo by one.
+ (*kappa)--;
+ if (fractionals < unsafe_interval.f()) {
+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
+ unsafe_interval.f(), fractionals, one.f(), unit);
+ }
+ }
+ }
+
+
+
+ // Generates (at most) requested_digits digits of input number w.
+ // w is a floating-point number (DiyFp), consisting of a significand and an
+ // exponent. Its exponent is bounded by kMinimalTargetExponent and
+ // kMaximalTargetExponent.
+ // Hence -60 <= w.e() <= -32.
+ //
+ // Returns false if it fails, in which case the generated digits in the buffer
+ // should not be used.
+ // Preconditions:
+ // * w is correct up to 1 ulp (unit in the last place). That
+ // is, its error must be strictly less than a unit of its last digit.
+ // * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+ //
+ // Postconditions: returns false if procedure fails.
+ // otherwise:
+ // * buffer is not null-terminated, but length contains the number of
+ // digits.
+ // * the representation in buffer is the most precise representation of
+ // requested_digits digits.
+ // * buffer contains at most requested_digits digits of w. If there are less
+ // than requested_digits digits then some trailing '0's have been removed.
+ // * kappa is such that
+ // w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
+ //
+ // Remark: This procedure takes into account the imprecision of its input
+ // numbers. If the precision is not enough to guarantee all the postconditions
+ // then false is returned. This usually happens rarely, but the failure-rate
+ // increases with higher requested_digits.
+ static bool DigitGenCounted(DiyFp w,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* kappa) {
+ ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+ ASSERT(kMinimalTargetExponent >= -60);
+ ASSERT(kMaximalTargetExponent <= -32);
+ // w is assumed to have an error less than 1 unit. Whenever w is scaled we
+ // also scale its error.
+ uint64_t w_error = 1;
+ // We cut the input number into two parts: the integral digits and the
+ // fractional digits. We don't emit any decimal separator, but adapt kappa
+ // instead. Example: instead of writing "1.2" we put "12" into the buffer and
+ // increase kappa by 1.
+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+ // Division by one is a shift.
+ uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());
+ // Modulo by one is an and.
+ uint64_t fractionals = w.f() & (one.f() - 1);
+ uint32_t divisor;
+ int divisor_exponent;
+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+ &divisor, &divisor_exponent);
+ *kappa = divisor_exponent + 1;
+ *length = 0;
+
+ // Loop invariant: buffer = w / 10^kappa (integer division)
+ // The invariant holds for the first iteration: kappa has been initialized
+ // with the divisor exponent + 1. And the divisor is the biggest power of ten
+ // that is smaller than 'integrals'.
+ while (*kappa > 0) {
+ int digit = integrals / divisor;
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ requested_digits--;
+ integrals %= divisor;
+ (*kappa)--;
+ // Note that kappa now equals the exponent of the divisor and that the
+ // invariant thus holds again.
+ if (requested_digits == 0) break;
+ divisor /= 10;
+ }
+
+ if (requested_digits == 0) {
+ uint64_t rest =
+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+ return RoundWeedCounted(buffer, *length, rest,
+ static_cast<uint64_t>(divisor) << -one.e(), w_error,
+ kappa);
+ }
+
+ // The integrals have been generated. We are at the point of the decimal
+ // separator. In the following loop we simply multiply the remaining digits by
+ // 10 and divide by one. We just need to pay attention to multiply associated
+ // data (the 'unit'), too.
+ // Note that the multiplication by 10 does not overflow, because w.e >= -60
+ // and thus one.e >= -60.
+ ASSERT(one.e() >= -60);
+ ASSERT(fractionals < one.f());
+ ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+ while (requested_digits > 0 && fractionals > w_error) {
+ fractionals *= 10;
+ w_error *= 10;
+ // Integer division by one.
+ int digit = static_cast<int>(fractionals >> -one.e());
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ requested_digits--;
+ fractionals &= one.f() - 1; // Modulo by one.
+ (*kappa)--;
+ }
+ if (requested_digits != 0) return false;
+ return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,
+ kappa);
+ }
+
+
+ // Provides a decimal representation of v.
+ // Returns true if it succeeds, otherwise the result cannot be trusted.
+ // There will be *length digits inside the buffer (not null-terminated).
+ // If the function returns true then
+ // v == (double) (buffer * 10^decimal_exponent).
+ // The digits in the buffer are the shortest representation possible: no
+ // 0.09999999999999999 instead of 0.1. The shorter representation will even be
+ // chosen even if the longer one would be closer to v.
+ // The last digit will be closest to the actual v. That is, even if several
+ // digits might correctly yield 'v' when read again, the closest will be
+ // computed.
+ static bool Grisu3(double v,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_exponent) {
+ DiyFp w = Double(v).AsNormalizedDiyFp();
+ // boundary_minus and boundary_plus are the boundaries between v and its
+ // closest floating-point neighbors. Any number strictly between
+ // boundary_minus and boundary_plus will round to v when convert to a double.
+ // Grisu3 will never output representations that lie exactly on a boundary.
+ DiyFp boundary_minus, boundary_plus;
+ Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ ASSERT(boundary_plus.e() == w.e());
+ DiyFp ten_mk; // Cached power of ten: 10^-k
+ int mk; // -k
+ int ten_mk_minimal_binary_exponent =
+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ int ten_mk_maximal_binary_exponent =
+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+ ten_mk_minimal_binary_exponent,
+ ten_mk_maximal_binary_exponent,
+ &ten_mk, &mk);
+ ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize) &&
+ (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize));
+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+ // off by a small amount.
+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e
+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+ ASSERT(scaled_w.e() ==
+ boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
+ // In theory it would be possible to avoid some recomputations by computing
+ // the difference between w and boundary_minus/plus (a power of 2) and to
+ // compute scaled_boundary_minus/plus by subtracting/adding from
+ // scaled_w. However the code becomes much less readable and the speed
+ // enhancements are not terriffic.
+ DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
+ DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);
+
+ // DigitGen will generate the digits of scaled_w. Therefore we have
+ // v == (double) (scaled_w * 10^-mk).
+ // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+ // integer than it will be updated. For instance if scaled_w == 1.23 then
+ // the buffer will be filled with "123" und the decimal_exponent will be
+ // decreased by 2.
+ int kappa;
+ bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+ buffer, length, &kappa);
+ *decimal_exponent = -mk + kappa;
+ return result;
+ }
+
+
+ // The "counted" version of grisu3 (see above) only generates requested_digits
+ // number of digits. This version does not generate the shortest representation,
+ // and with enough requested digits 0.1 will at some point print as 0.9999999...
+ // Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
+ // therefore the rounding strategy for halfway cases is irrelevant.
+ static bool Grisu3Counted(double v,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_exponent) {
+ DiyFp w = Double(v).AsNormalizedDiyFp();
+ DiyFp ten_mk; // Cached power of ten: 10^-k
+ int mk; // -k
+ int ten_mk_minimal_binary_exponent =
+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ int ten_mk_maximal_binary_exponent =
+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+ ten_mk_minimal_binary_exponent,
+ ten_mk_maximal_binary_exponent,
+ &ten_mk, &mk);
+ ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize) &&
+ (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize));
+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+ // off by a small amount.
+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e
+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+
+ // We now have (double) (scaled_w * 10^-mk).
+ // DigitGen will generate the first requested_digits digits of scaled_w and
+ // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
+ // will not always be exactly the same since DigitGenCounted only produces a
+ // limited number of digits.)
+ int kappa;
+ bool result = DigitGenCounted(scaled_w, requested_digits,
+ buffer, length, &kappa);
+ *decimal_exponent = -mk + kappa;
+ return result;
+ }
+
+
+ bool FastDtoa(double v,
+ FastDtoaMode mode,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_point) {
+ ASSERT(v > 0);
+ ASSERT(!Double(v).IsSpecial());
+
+ bool result = false;
+ int decimal_exponent = 0;
+ switch (mode) {
+ case FAST_DTOA_SHORTEST:
+ result = Grisu3(v, buffer, length, &decimal_exponent);
+ break;
+ case FAST_DTOA_PRECISION:
+ result = Grisu3Counted(v, requested_digits,
+ buffer, length, &decimal_exponent);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (result) {
+ *decimal_point = *length + decimal_exponent;
+ buffer[*length] = '\0';
+ }
+ return result;
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.h b/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.h
new file mode 100644
index 000000000..876a9f382
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/fast-dtoa.h
@@ -0,0 +1,88 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_FAST_DTOA_H_
+#define DOUBLE_CONVERSION_FAST_DTOA_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ enum FastDtoaMode {
+ // Computes the shortest representation of the given input. The returned
+ // result will be the most accurate number of this length. Longer
+ // representations might be more accurate.
+ FAST_DTOA_SHORTEST,
+ // Computes a representation where the precision (number of digits) is
+ // given as input. The precision is independent of the decimal point.
+ FAST_DTOA_PRECISION
+ };
+
+ // FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
+ // include the terminating '\0' character.
+ static const int kFastDtoaMaximalLength = 17;
+
+ // Provides a decimal representation of v.
+ // The result should be interpreted as buffer * 10^(point - length).
+ //
+ // Precondition:
+ // * v must be a strictly positive finite double.
+ //
+ // Returns true if it succeeds, otherwise the result can not be trusted.
+ // There will be *length digits inside the buffer followed by a null terminator.
+ // If the function returns true and mode equals
+ // - FAST_DTOA_SHORTEST, then
+ // the parameter requested_digits is ignored.
+ // The result satisfies
+ // v == (double) (buffer * 10^(point - length)).
+ // The digits in the buffer are the shortest representation possible. E.g.
+ // if 0.099999999999 and 0.1 represent the same double then "1" is returned
+ // with point = 0.
+ // The last digit will be closest to the actual v. That is, even if several
+ // digits might correctly yield 'v' when read again, the buffer will contain
+ // the one closest to v.
+ // - FAST_DTOA_PRECISION, then
+ // the buffer contains requested_digits digits.
+ // the difference v - (buffer * 10^(point-length)) is closest to zero for
+ // all possible representations of requested_digits digits.
+ // If there are two values that are equally close, then FastDtoa returns
+ // false.
+ // For both modes the buffer must be large enough to hold the result.
+ bool FastDtoa(double d,
+ FastDtoaMode mode,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_point);
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_FAST_DTOA_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.cc b/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.cc
new file mode 100644
index 000000000..40b7180e5
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.cc
@@ -0,0 +1,410 @@
+// Copyright 2010 the V8 project authors. 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 <math.h>
+
+#include "UnusedParam.h"
+#include "fixed-dtoa.h"
+#include "double.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // Represents a 128bit type. This class should be replaced by a native type on
+ // platforms that support 128bit integers.
+ class UInt128 {
+ public:
+ UInt128() : high_bits_(0), low_bits_(0) { }
+ UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { }
+
+ void Multiply(uint32_t multiplicand) {
+ uint64_t accumulator;
+
+ accumulator = (low_bits_ & kMask32) * multiplicand;
+ uint32_t part = static_cast<uint32_t>(accumulator & kMask32);
+ accumulator >>= 32;
+ accumulator = accumulator + (low_bits_ >> 32) * multiplicand;
+ low_bits_ = (accumulator << 32) + part;
+ accumulator >>= 32;
+ accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
+ part = static_cast<uint32_t>(accumulator & kMask32);
+ accumulator >>= 32;
+ accumulator = accumulator + (high_bits_ >> 32) * multiplicand;
+ high_bits_ = (accumulator << 32) + part;
+ ASSERT((accumulator >> 32) == 0);
+ }
+
+ void Shift(int shift_amount) {
+ ASSERT(-64 <= shift_amount && shift_amount <= 64);
+ if (shift_amount == 0) {
+ return;
+ } else if (shift_amount == -64) {
+ high_bits_ = low_bits_;
+ low_bits_ = 0;
+ } else if (shift_amount == 64) {
+ low_bits_ = high_bits_;
+ high_bits_ = 0;
+ } else if (shift_amount <= 0) {
+ high_bits_ <<= -shift_amount;
+ high_bits_ += low_bits_ >> (64 + shift_amount);
+ low_bits_ <<= -shift_amount;
+ } else {
+ low_bits_ >>= shift_amount;
+ low_bits_ += high_bits_ << (64 - shift_amount);
+ high_bits_ >>= shift_amount;
+ }
+ }
+
+ // Modifies *this to *this MOD (2^power).
+ // Returns *this DIV (2^power).
+ int DivModPowerOf2(int power) {
+ if (power >= 64) {
+ int result = static_cast<int>(high_bits_ >> (power - 64));
+ high_bits_ -= static_cast<uint64_t>(result) << (power - 64);
+ return result;
+ } else {
+ uint64_t part_low = low_bits_ >> power;
+ uint64_t part_high = high_bits_ << (64 - power);
+ int result = static_cast<int>(part_low + part_high);
+ high_bits_ = 0;
+ low_bits_ -= part_low << power;
+ return result;
+ }
+ }
+
+ bool IsZero() const {
+ return high_bits_ == 0 && low_bits_ == 0;
+ }
+
+ int BitAt(int position) {
+ if (position >= 64) {
+ return static_cast<int>(high_bits_ >> (position - 64)) & 1;
+ } else {
+ return static_cast<int>(low_bits_ >> position) & 1;
+ }
+ }
+
+ private:
+ static const uint64_t kMask32 = 0xFFFFFFFF;
+ // Value == (high_bits_ << 64) + low_bits_
+ uint64_t high_bits_;
+ uint64_t low_bits_;
+ };
+
+
+ static const int kDoubleSignificandSize = 53; // Includes the hidden bit.
+
+
+ static void FillDigits32FixedLength(uint32_t number, int requested_length,
+ Vector<char> buffer, int* length) {
+ for (int i = requested_length - 1; i >= 0; --i) {
+ buffer[(*length) + i] = '0' + number % 10;
+ number /= 10;
+ }
+ *length += requested_length;
+ }
+
+
+ static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) {
+ int number_length = 0;
+ // We fill the digits in reverse order and exchange them afterwards.
+ while (number != 0) {
+ int digit = number % 10;
+ number /= 10;
+ buffer[(*length) + number_length] = '0' + digit;
+ number_length++;
+ }
+ // Exchange the digits.
+ int i = *length;
+ int j = *length + number_length - 1;
+ while (i < j) {
+ char tmp = buffer[i];
+ buffer[i] = buffer[j];
+ buffer[j] = tmp;
+ i++;
+ j--;
+ }
+ *length += number_length;
+ }
+
+
+ static void FillDigits64FixedLength(uint64_t number, int requested_length,
+ Vector<char> buffer, int* length) {
+ UNUSED_PARAM(requested_length);
+ const uint32_t kTen7 = 10000000;
+ // For efficiency cut the number into 3 uint32_t parts, and print those.
+ uint32_t part2 = static_cast<uint32_t>(number % kTen7);
+ number /= kTen7;
+ uint32_t part1 = static_cast<uint32_t>(number % kTen7);
+ uint32_t part0 = static_cast<uint32_t>(number / kTen7);
+
+ FillDigits32FixedLength(part0, 3, buffer, length);
+ FillDigits32FixedLength(part1, 7, buffer, length);
+ FillDigits32FixedLength(part2, 7, buffer, length);
+ }
+
+
+ static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) {
+ const uint32_t kTen7 = 10000000;
+ // For efficiency cut the number into 3 uint32_t parts, and print those.
+ uint32_t part2 = static_cast<uint32_t>(number % kTen7);
+ number /= kTen7;
+ uint32_t part1 = static_cast<uint32_t>(number % kTen7);
+ uint32_t part0 = static_cast<uint32_t>(number / kTen7);
+
+ if (part0 != 0) {
+ FillDigits32(part0, buffer, length);
+ FillDigits32FixedLength(part1, 7, buffer, length);
+ FillDigits32FixedLength(part2, 7, buffer, length);
+ } else if (part1 != 0) {
+ FillDigits32(part1, buffer, length);
+ FillDigits32FixedLength(part2, 7, buffer, length);
+ } else {
+ FillDigits32(part2, buffer, length);
+ }
+ }
+
+
+ static void RoundUp(Vector<char> buffer, int* length, int* decimal_point) {
+ // An empty buffer represents 0.
+ if (*length == 0) {
+ buffer[0] = '1';
+ *decimal_point = 1;
+ *length = 1;
+ return;
+ }
+ // Round the last digit until we either have a digit that was not '9' or until
+ // we reached the first digit.
+ buffer[(*length) - 1]++;
+ for (int i = (*length) - 1; i > 0; --i) {
+ if (buffer[i] != '0' + 10) {
+ return;
+ }
+ buffer[i] = '0';
+ buffer[i - 1]++;
+ }
+ // If the first digit is now '0' + 10, we would need to set it to '0' and add
+ // a '1' in front. However we reach the first digit only if all following
+ // digits had been '9' before rounding up. Now all trailing digits are '0' and
+ // we simply switch the first digit to '1' and update the decimal-point
+ // (indicating that the point is now one digit to the right).
+ if (buffer[0] == '0' + 10) {
+ buffer[0] = '1';
+ (*decimal_point)++;
+ }
+ }
+
+
+ // The given fractionals number represents a fixed-point number with binary
+ // point at bit (-exponent).
+ // Preconditions:
+ // -128 <= exponent <= 0.
+ // 0 <= fractionals * 2^exponent < 1
+ // The buffer holds the result.
+ // The function will round its result. During the rounding-process digits not
+ // generated by this function might be updated, and the decimal-point variable
+ // might be updated. If this function generates the digits 99 and the buffer
+ // already contained "199" (thus yielding a buffer of "19999") then a
+ // rounding-up will change the contents of the buffer to "20000".
+ static void FillFractionals(uint64_t fractionals, int exponent,
+ int fractional_count, Vector<char> buffer,
+ int* length, int* decimal_point) {
+ ASSERT(-128 <= exponent && exponent <= 0);
+ // 'fractionals' is a fixed-point number, with binary point at bit
+ // (-exponent). Inside the function the non-converted remainder of fractionals
+ // is a fixed-point number, with binary point at bit 'point'.
+ if (-exponent <= 64) {
+ // One 64 bit number is sufficient.
+ ASSERT(fractionals >> 56 == 0);
+ int point = -exponent;
+ for (int i = 0; i < fractional_count; ++i) {
+ if (fractionals == 0) break;
+ // Instead of multiplying by 10 we multiply by 5 and adjust the point
+ // location. This way the fractionals variable will not overflow.
+ // Invariant at the beginning of the loop: fractionals < 2^point.
+ // Initially we have: point <= 64 and fractionals < 2^56
+ // After each iteration the point is decremented by one.
+ // Note that 5^3 = 125 < 128 = 2^7.
+ // Therefore three iterations of this loop will not overflow fractionals
+ // (even without the subtraction at the end of the loop body). At this
+ // time point will satisfy point <= 61 and therefore fractionals < 2^point
+ // and any further multiplication of fractionals by 5 will not overflow.
+ fractionals *= 5;
+ point--;
+ int digit = static_cast<int>(fractionals >> point);
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ fractionals -= static_cast<uint64_t>(digit) << point;
+ }
+ // If the first bit after the point is set we have to round up.
+ if (((fractionals >> (point - 1)) & 1) == 1) {
+ RoundUp(buffer, length, decimal_point);
+ }
+ } else { // We need 128 bits.
+ ASSERT(64 < -exponent && -exponent <= 128);
+ UInt128 fractionals128 = UInt128(fractionals, 0);
+ fractionals128.Shift(-exponent - 64);
+ int point = 128;
+ for (int i = 0; i < fractional_count; ++i) {
+ if (fractionals128.IsZero()) break;
+ // As before: instead of multiplying by 10 we multiply by 5 and adjust the
+ // point location.
+ // This multiplication will not overflow for the same reasons as before.
+ fractionals128.Multiply(5);
+ point--;
+ int digit = fractionals128.DivModPowerOf2(point);
+ buffer[*length] = '0' + digit;
+ (*length)++;
+ }
+ if (fractionals128.BitAt(point - 1) == 1) {
+ RoundUp(buffer, length, decimal_point);
+ }
+ }
+ }
+
+
+ // Removes leading and trailing zeros.
+ // If leading zeros are removed then the decimal point position is adjusted.
+ static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) {
+ while (*length > 0 && buffer[(*length) - 1] == '0') {
+ (*length)--;
+ }
+ int first_non_zero = 0;
+ while (first_non_zero < *length && buffer[first_non_zero] == '0') {
+ first_non_zero++;
+ }
+ if (first_non_zero != 0) {
+ for (int i = first_non_zero; i < *length; ++i) {
+ buffer[i - first_non_zero] = buffer[i];
+ }
+ *length -= first_non_zero;
+ *decimal_point -= first_non_zero;
+ }
+ }
+
+
+ bool FastFixedDtoa(double v,
+ int fractional_count,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_point) {
+ const uint32_t kMaxUInt32 = 0xFFFFFFFF;
+ uint64_t significand = Double(v).Significand();
+ int exponent = Double(v).Exponent();
+ // v = significand * 2^exponent (with significand a 53bit integer).
+ // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
+ // don't know how to compute the representation. 2^73 ~= 9.5*10^21.
+ // If necessary this limit could probably be increased, but we don't need
+ // more.
+ if (exponent > 20) return false;
+ if (fractional_count > 20) return false;
+ *length = 0;
+ // At most kDoubleSignificandSize bits of the significand are non-zero.
+ // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
+ // bits: 0..11*..0xxx..53*..xx
+ if (exponent + kDoubleSignificandSize > 64) {
+ // The exponent must be > 11.
+ //
+ // We know that v = significand * 2^exponent.
+ // And the exponent > 11.
+ // We simplify the task by dividing v by 10^17.
+ // The quotient delivers the first digits, and the remainder fits into a 64
+ // bit number.
+ // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
+ const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17
+ uint64_t divisor = kFive17;
+ int divisor_power = 17;
+ uint64_t dividend = significand;
+ uint32_t quotient;
+ uint64_t remainder;
+ // Let v = f * 2^e with f == significand and e == exponent.
+ // Then need q (quotient) and r (remainder) as follows:
+ // v = q * 10^17 + r
+ // f * 2^e = q * 10^17 + r
+ // f * 2^e = q * 5^17 * 2^17 + r
+ // If e > 17 then
+ // f * 2^(e-17) = q * 5^17 + r/2^17
+ // else
+ // f = q * 5^17 * 2^(17-e) + r/2^e
+ if (exponent > divisor_power) {
+ // We only allow exponents of up to 20 and therefore (17 - e) <= 3
+ dividend <<= exponent - divisor_power;
+ quotient = static_cast<uint32_t>(dividend / divisor);
+ remainder = (dividend % divisor) << divisor_power;
+ } else {
+ divisor <<= divisor_power - exponent;
+ quotient = static_cast<uint32_t>(dividend / divisor);
+ remainder = (dividend % divisor) << exponent;
+ }
+ FillDigits32(quotient, buffer, length);
+ FillDigits64FixedLength(remainder, divisor_power, buffer, length);
+ *decimal_point = *length;
+ } else if (exponent >= 0) {
+ // 0 <= exponent <= 11
+ significand <<= exponent;
+ FillDigits64(significand, buffer, length);
+ *decimal_point = *length;
+ } else if (exponent > -kDoubleSignificandSize) {
+ // We have to cut the number.
+ uint64_t integrals = significand >> -exponent;
+ uint64_t fractionals = significand - (integrals << -exponent);
+ if (integrals > kMaxUInt32) {
+ FillDigits64(integrals, buffer, length);
+ } else {
+ FillDigits32(static_cast<uint32_t>(integrals), buffer, length);
+ }
+ *decimal_point = *length;
+ FillFractionals(fractionals, exponent, fractional_count,
+ buffer, length, decimal_point);
+ } else if (exponent < -128) {
+ // This configuration (with at most 20 digits) means that all digits must be
+ // 0.
+ ASSERT(fractional_count <= 20);
+ buffer[0] = '\0';
+ *length = 0;
+ *decimal_point = -fractional_count;
+ } else {
+ *decimal_point = 0;
+ FillFractionals(significand, exponent, fractional_count,
+ buffer, length, decimal_point);
+ }
+ TrimZeros(buffer, length, decimal_point);
+ buffer[*length] = '\0';
+ if ((*length) == 0) {
+ // The string is empty and the decimal_point thus has no importance. Mimick
+ // Gay's dtoa and and set it to -fractional_count.
+ *decimal_point = -fractional_count;
+ }
+ return true;
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.h b/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.h
new file mode 100644
index 000000000..8c0adb758
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/fixed-dtoa.h
@@ -0,0 +1,60 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_FIXED_DTOA_H_
+#define DOUBLE_CONVERSION_FIXED_DTOA_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // Produces digits necessary to print a given number with
+ // 'fractional_count' digits after the decimal point.
+ // The buffer must be big enough to hold the result plus one terminating null
+ // character.
+ //
+ // The produced digits might be too short in which case the caller has to fill
+ // the gaps with '0's.
+ // Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and
+ // decimal_point = -2.
+ // Halfway cases are rounded towards +/-Infinity (away from 0). The call
+ // FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0.
+ // The returned buffer may contain digits that would be truncated from the
+ // shortest representation of the input.
+ //
+ // This method only works for some parameters. If it can't handle the input it
+ // returns false. The output is null-terminated when the function succeeds.
+ bool FastFixedDtoa(double v, int fractional_count,
+ Vector<char> buffer, int* length, int* decimal_point);
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_FIXED_DTOA_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/strtod.cc b/Source/JavaScriptCore/wtf/dtoa/strtod.cc
new file mode 100644
index 000000000..477e7158c
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/strtod.cc
@@ -0,0 +1,447 @@
+// Copyright 2010 the V8 project authors. 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 <stdarg.h>
+#include <limits.h>
+
+#include "strtod.h"
+#include "bignum.h"
+#include "cached-powers.h"
+#include "double.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // 2^53 = 9007199254740992.
+ // Any integer with at most 15 decimal digits will hence fit into a double
+ // (which has a 53bit significand) without loss of precision.
+ static const int kMaxExactDoubleIntegerDecimalDigits = 15;
+ // 2^64 = 18446744073709551616 > 10^19
+ static const int kMaxUint64DecimalDigits = 19;
+
+ // Max double: 1.7976931348623157 x 10^308
+ // Min non-zero double: 4.9406564584124654 x 10^-324
+ // Any x >= 10^309 is interpreted as +infinity.
+ // Any x <= 10^-324 is interpreted as 0.
+ // Note that 2.5e-324 (despite being smaller than the min double) will be read
+ // as non-zero (equal to the min non-zero double).
+ static const int kMaxDecimalPower = 309;
+ static const int kMinDecimalPower = -324;
+
+ // 2^64 = 18446744073709551616
+ static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
+
+
+ static const double exact_powers_of_ten[] = {
+ 1.0, // 10^0
+ 10.0,
+ 100.0,
+ 1000.0,
+ 10000.0,
+ 100000.0,
+ 1000000.0,
+ 10000000.0,
+ 100000000.0,
+ 1000000000.0,
+ 10000000000.0, // 10^10
+ 100000000000.0,
+ 1000000000000.0,
+ 10000000000000.0,
+ 100000000000000.0,
+ 1000000000000000.0,
+ 10000000000000000.0,
+ 100000000000000000.0,
+ 1000000000000000000.0,
+ 10000000000000000000.0,
+ 100000000000000000000.0, // 10^20
+ 1000000000000000000000.0,
+ // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
+ 10000000000000000000000.0
+ };
+ static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
+
+ // Maximum number of significant digits in the decimal representation.
+ // In fact the value is 772 (see conversions.cc), but to give us some margin
+ // we round up to 780.
+ static const int kMaxSignificantDecimalDigits = 780;
+
+ static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
+ for (int i = 0; i < buffer.length(); i++) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(i, buffer.length());
+ }
+ }
+ return Vector<const char>(buffer.start(), 0);
+ }
+
+
+ static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+ for (int i = buffer.length() - 1; i >= 0; --i) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(0, i + 1);
+ }
+ }
+ return Vector<const char>(buffer.start(), 0);
+ }
+
+
+ static void TrimToMaxSignificantDigits(Vector<const char> buffer,
+ int exponent,
+ char* significant_buffer,
+ int* significant_exponent) {
+ for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
+ significant_buffer[i] = buffer[i];
+ }
+ // The input buffer has been trimmed. Therefore the last digit must be
+ // different from '0'.
+ ASSERT(buffer[buffer.length() - 1] != '0');
+ // Set the last digit to be non-zero. This is sufficient to guarantee
+ // correct rounding.
+ significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
+ *significant_exponent =
+ exponent + (buffer.length() - kMaxSignificantDecimalDigits);
+ }
+
+ // Reads digits from the buffer and converts them to a uint64.
+ // Reads in as many digits as fit into a uint64.
+ // When the string starts with "1844674407370955161" no further digit is read.
+ // Since 2^64 = 18446744073709551616 it would still be possible read another
+ // digit if it was less or equal than 6, but this would complicate the code.
+ static uint64_t ReadUint64(Vector<const char> buffer,
+ int* number_of_read_digits) {
+ uint64_t result = 0;
+ int i = 0;
+ while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {
+ int digit = buffer[i++] - '0';
+ ASSERT(0 <= digit && digit <= 9);
+ result = 10 * result + digit;
+ }
+ *number_of_read_digits = i;
+ return result;
+ }
+
+
+ // Reads a DiyFp from the buffer.
+ // The returned DiyFp is not necessarily normalized.
+ // If remaining_decimals is zero then the returned DiyFp is accurate.
+ // Otherwise it has been rounded and has error of at most 1/2 ulp.
+ static void ReadDiyFp(Vector<const char> buffer,
+ DiyFp* result,
+ int* remaining_decimals) {
+ int read_digits;
+ uint64_t significand = ReadUint64(buffer, &read_digits);
+ if (buffer.length() == read_digits) {
+ *result = DiyFp(significand, 0);
+ *remaining_decimals = 0;
+ } else {
+ // Round the significand.
+ if (buffer[read_digits] >= '5') {
+ significand++;
+ }
+ // Compute the binary exponent.
+ int exponent = 0;
+ *result = DiyFp(significand, exponent);
+ *remaining_decimals = buffer.length() - read_digits;
+ }
+ }
+
+
+ static bool DoubleStrtod(Vector<const char> trimmed,
+ int exponent,
+ double* result) {
+#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+ // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
+ // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
+ // result is not accurate.
+ // We know that Windows32 uses 64 bits and is therefore accurate.
+ // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
+ // the same problem.
+ return false;
+#endif
+ if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
+ int read_digits;
+ // The trimmed input fits into a double.
+ // If the 10^exponent (resp. 10^-exponent) fits into a double too then we
+ // can compute the result-double simply by multiplying (resp. dividing) the
+ // two numbers.
+ // This is possible because IEEE guarantees that floating-point operations
+ // return the best possible approximation.
+ if (exponent < 0 && -exponent < kExactPowersOfTenSize) {
+ // 10^-exponent fits into a double.
+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result /= exact_powers_of_ten[-exponent];
+ return true;
+ }
+ if (0 <= exponent && exponent < kExactPowersOfTenSize) {
+ // 10^exponent fits into a double.
+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result *= exact_powers_of_ten[exponent];
+ return true;
+ }
+ int remaining_digits =
+ kMaxExactDoubleIntegerDecimalDigits - trimmed.length();
+ if ((0 <= exponent) &&
+ (exponent - remaining_digits < kExactPowersOfTenSize)) {
+ // The trimmed string was short and we can multiply it with
+ // 10^remaining_digits. As a result the remaining exponent now fits
+ // into a double too.
+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result *= exact_powers_of_ten[remaining_digits];
+ *result *= exact_powers_of_ten[exponent - remaining_digits];
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ // Returns 10^exponent as an exact DiyFp.
+ // The given exponent must be in the range [1; kDecimalExponentDistance[.
+ static DiyFp AdjustmentPowerOfTen(int exponent) {
+ ASSERT(0 < exponent);
+ ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
+ // Simply hardcode the remaining powers for the given decimal exponent
+ // distance.
+ ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
+ switch (exponent) {
+ case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);
+ case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);
+ case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);
+ case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);
+ case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);
+ case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);
+ case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
+ default:
+ UNREACHABLE();
+ return DiyFp(0, 0);
+ }
+ }
+
+
+ // If the function returns true then the result is the correct double.
+ // Otherwise it is either the correct double or the double that is just below
+ // the correct double.
+ static bool DiyFpStrtod(Vector<const char> buffer,
+ int exponent,
+ double* result) {
+ DiyFp input;
+ int remaining_decimals;
+ ReadDiyFp(buffer, &input, &remaining_decimals);
+ // Since we may have dropped some digits the input is not accurate.
+ // If remaining_decimals is different than 0 than the error is at most
+ // .5 ulp (unit in the last place).
+ // We don't want to deal with fractions and therefore keep a common
+ // denominator.
+ const int kDenominatorLog = 3;
+ const int kDenominator = 1 << kDenominatorLog;
+ // Move the remaining decimals into the exponent.
+ exponent += remaining_decimals;
+ int error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
+
+ int old_e = input.e();
+ input.Normalize();
+ error <<= old_e - input.e();
+
+ ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent);
+ if (exponent < PowersOfTenCache::kMinDecimalExponent) {
+ *result = 0.0;
+ return true;
+ }
+ DiyFp cached_power;
+ int cached_decimal_exponent;
+ PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent,
+ &cached_power,
+ &cached_decimal_exponent);
+
+ if (cached_decimal_exponent != exponent) {
+ int adjustment_exponent = exponent - cached_decimal_exponent;
+ DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent);
+ input.Multiply(adjustment_power);
+ if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) {
+ // The product of input with the adjustment power fits into a 64 bit
+ // integer.
+ ASSERT(DiyFp::kSignificandSize == 64);
+ } else {
+ // The adjustment power is exact. There is hence only an error of 0.5.
+ error += kDenominator / 2;
+ }
+ }
+
+ input.Multiply(cached_power);
+ // The error introduced by a multiplication of a*b equals
+ // error_a + error_b + error_a*error_b/2^64 + 0.5
+ // Substituting a with 'input' and b with 'cached_power' we have
+ // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp),
+ // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64
+ int error_b = kDenominator / 2;
+ int error_ab = (error == 0 ? 0 : 1); // We round up to 1.
+ int fixed_error = kDenominator / 2;
+ error += error_b + error_ab + fixed_error;
+
+ old_e = input.e();
+ input.Normalize();
+ error <<= old_e - input.e();
+
+ // See if the double's significand changes if we add/subtract the error.
+ int order_of_magnitude = DiyFp::kSignificandSize + input.e();
+ int effective_significand_size =
+ Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude);
+ int precision_digits_count =
+ DiyFp::kSignificandSize - effective_significand_size;
+ if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) {
+ // This can only happen for very small denormals. In this case the
+ // half-way multiplied by the denominator exceeds the range of an uint64.
+ // Simply shift everything to the right.
+ int shift_amount = (precision_digits_count + kDenominatorLog) -
+ DiyFp::kSignificandSize + 1;
+ input.set_f(input.f() >> shift_amount);
+ input.set_e(input.e() + shift_amount);
+ // We add 1 for the lost precision of error, and kDenominator for
+ // the lost precision of input.f().
+ error = (error >> shift_amount) + 1 + kDenominator;
+ precision_digits_count -= shift_amount;
+ }
+ // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too.
+ ASSERT(DiyFp::kSignificandSize == 64);
+ ASSERT(precision_digits_count < 64);
+ uint64_t one64 = 1;
+ uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1;
+ uint64_t precision_bits = input.f() & precision_bits_mask;
+ uint64_t half_way = one64 << (precision_digits_count - 1);
+ precision_bits *= kDenominator;
+ half_way *= kDenominator;
+ DiyFp rounded_input(input.f() >> precision_digits_count,
+ input.e() + precision_digits_count);
+ if (precision_bits >= half_way + error) {
+ rounded_input.set_f(rounded_input.f() + 1);
+ }
+ // If the last_bits are too close to the half-way case than we are too
+ // inaccurate and round down. In this case we return false so that we can
+ // fall back to a more precise algorithm.
+
+ *result = Double(rounded_input).value();
+ if (half_way - error < precision_bits && precision_bits < half_way + error) {
+ // Too imprecise. The caller will have to fall back to a slower version.
+ // However the returned number is guaranteed to be either the correct
+ // double, or the next-lower double.
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+ // Returns the correct double for the buffer*10^exponent.
+ // The variable guess should be a close guess that is either the correct double
+ // or its lower neighbor (the nearest double less than the correct one).
+ // Preconditions:
+ // buffer.length() + exponent <= kMaxDecimalPower + 1
+ // buffer.length() + exponent > kMinDecimalPower
+ // buffer.length() <= kMaxDecimalSignificantDigits
+ static double BignumStrtod(Vector<const char> buffer,
+ int exponent,
+ double guess) {
+ if (guess == Double::Infinity()) {
+ return guess;
+ }
+
+ DiyFp upper_boundary = Double(guess).UpperBoundary();
+
+ ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+ ASSERT(buffer.length() + exponent > kMinDecimalPower);
+ ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
+ // Make sure that the Bignum will be able to hold all our numbers.
+ // Our Bignum implementation has a separate field for exponents. Shifts will
+ // consume at most one bigit (< 64 bits).
+ // ln(10) == 3.3219...
+ ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
+ Bignum input;
+ Bignum boundary;
+ input.AssignDecimalString(buffer);
+ boundary.AssignUInt64(upper_boundary.f());
+ if (exponent >= 0) {
+ input.MultiplyByPowerOfTen(exponent);
+ } else {
+ boundary.MultiplyByPowerOfTen(-exponent);
+ }
+ if (upper_boundary.e() > 0) {
+ boundary.ShiftLeft(upper_boundary.e());
+ } else {
+ input.ShiftLeft(-upper_boundary.e());
+ }
+ int comparison = Bignum::Compare(input, boundary);
+ if (comparison < 0) {
+ return guess;
+ } else if (comparison > 0) {
+ return Double(guess).NextDouble();
+ } else if ((Double(guess).Significand() & 1) == 0) {
+ // Round towards even.
+ return guess;
+ } else {
+ return Double(guess).NextDouble();
+ }
+ }
+
+
+ double Strtod(Vector<const char> buffer, int exponent) {
+ Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
+ Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
+ exponent += left_trimmed.length() - trimmed.length();
+ if (trimmed.length() == 0) return 0.0;
+ if (trimmed.length() > kMaxSignificantDecimalDigits) {
+ char significant_buffer[kMaxSignificantDecimalDigits];
+ int significant_exponent;
+ TrimToMaxSignificantDigits(trimmed, exponent,
+ significant_buffer, &significant_exponent);
+ return Strtod(Vector<const char>(significant_buffer,
+ kMaxSignificantDecimalDigits),
+ significant_exponent);
+ }
+ if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
+ return Double::Infinity();
+ }
+ if (exponent + trimmed.length() <= kMinDecimalPower) {
+ return 0.0;
+ }
+
+ double guess;
+ if (DoubleStrtod(trimmed, exponent, &guess) ||
+ DiyFpStrtod(trimmed, exponent, &guess)) {
+ return guess;
+ }
+ return BignumStrtod(trimmed, exponent, guess);
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/dtoa/strtod.h b/Source/JavaScriptCore/wtf/dtoa/strtod.h
new file mode 100644
index 000000000..8ed350ad8
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/strtod.h
@@ -0,0 +1,45 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_STRTOD_H_
+#define DOUBLE_CONVERSION_STRTOD_H_
+
+#include "utils.h"
+
+namespace WTF {
+
+namespace double_conversion {
+
+ // The buffer must only contain digits in the range [0-9]. It must not
+ // contain a dot or a sign. It must not start with '0', and must not be empty.
+ double Strtod(Vector<const char> buffer, int exponent);
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_STRTOD_H_
diff --git a/Source/JavaScriptCore/wtf/dtoa/utils.h b/Source/JavaScriptCore/wtf/dtoa/utils.h
new file mode 100644
index 000000000..d5cfe9c29
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/dtoa/utils.h
@@ -0,0 +1,310 @@
+// Copyright 2010 the V8 project authors. 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 DOUBLE_CONVERSION_UTILS_H_
+#define DOUBLE_CONVERSION_UTILS_H_
+
+#include "Assertions.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define UNIMPLEMENTED ASSERT_NOT_REACHED
+#define UNREACHABLE ASSERT_NOT_REACHED
+
+// Double operations detection based on target architecture.
+// Linux uses a 80bit wide floating point stack on x86. This induces double
+// rounding, which in turn leads to wrong results.
+// An easy way to test if the floating-point operations are correct is to
+// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
+// the result is equal to 89255e-22.
+// The best way to test this, is to create a division-function and to compare
+// the output of the division with the expected result. (Inlining must be
+// disabled.)
+// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
+#if defined(_M_X64) || defined(__x86_64__) || \
+defined(__ARMEL__) || \
+defined(_MIPS_ARCH_MIPS32R2)
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#elif CPU(MIPS) || CPU(PPC) || CPU(PPC64) || OS(WINCE) || CPU(SH4) || CPU(S390) || CPU(S390X)
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#elif defined(_M_IX86) || defined(__i386__)
+#if defined(_WIN32)
+// Windows uses a 64bit wide floating point stack.
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#else
+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
+#endif // _WIN32
+#else
+#error Target architecture was not detected as supported by Double-Conversion.
+#endif
+
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t; // NOLINT
+typedef unsigned short uint16_t; // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+// intptr_t and friends are defined in crtdefs.h through stdio.h.
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+// The following macro works on both 32 and 64-bit platforms.
+// Usage: instead of writing 0x1234567890123456
+// write UINT64_2PART_C(0x12345678,90123456);
+#define UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
+
+
+// The expression ARRAY_SIZE(a) is a compile-time constant of type
+// size_t which represents the number of elements of the given
+// array. You should only use ARRAY_SIZE on statically allocated
+// arrays.
+#define ARRAY_SIZE(a) \
+((sizeof(a) / sizeof(*(a))) / \
+static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+TypeName(const TypeName&); \
+void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+TypeName(); \
+DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+namespace WTF {
+
+namespace double_conversion {
+
+ static const int kCharSize = sizeof(char);
+
+ // Returns the maximum of the two parameters.
+ template <typename T>
+ static T Max(T a, T b) {
+ return a < b ? b : a;
+ }
+
+
+ // Returns the minimum of the two parameters.
+ template <typename T>
+ static T Min(T a, T b) {
+ return a < b ? a : b;
+ }
+
+
+ inline int StrLength(const char* string) {
+ size_t length = strlen(string);
+ ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
+ return static_cast<int>(length);
+ }
+
+ // This is a simplified version of V8's Vector class.
+ template <typename T>
+ class Vector {
+ public:
+ Vector() : start_(NULL), length_(0) {}
+ Vector(T* data, int length) : start_(data), length_(length) {
+ ASSERT(length == 0 || (length > 0 && data != NULL));
+ }
+
+ // Returns a vector using the same backing storage as this one,
+ // spanning from and including 'from', to but not including 'to'.
+ Vector<T> SubVector(int from, int to) {
+ ASSERT(to <= length_);
+ ASSERT(from < to);
+ ASSERT(0 <= from);
+ return Vector<T>(start() + from, to - from);
+ }
+
+ // Returns the length of the vector.
+ int length() const { return length_; }
+
+ // Returns whether or not the vector is empty.
+ bool is_empty() const { return length_ == 0; }
+
+ // Returns the pointer to the start of the data in the vector.
+ T* start() const { return start_; }
+
+ // Access individual vector elements - checks bounds in debug mode.
+ T& operator[](int index) const {
+ ASSERT(0 <= index && index < length_);
+ return start_[index];
+ }
+
+ T& first() { return start_[0]; }
+
+ T& last() { return start_[length_ - 1]; }
+
+ private:
+ T* start_;
+ int length_;
+ };
+
+
+ // Helper class for building result strings in a character buffer. The
+ // purpose of the class is to use safe operations that checks the
+ // buffer bounds on all operations in debug mode.
+ class StringBuilder {
+ public:
+ StringBuilder(char* buffer, int size)
+ : buffer_(buffer, size), position_(0) { }
+
+ ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+ int size() const { return buffer_.length(); }
+
+ // Get the current position in the builder.
+ int position() const {
+ ASSERT(!is_finalized());
+ return position_;
+ }
+
+ // Set the current position in the builder.
+ void SetPosition(int position)
+ {
+ ASSERT(!is_finalized());
+ ASSERT(position < size());
+ position_ = position;
+ }
+
+ // Reset the position.
+ void Reset() { position_ = 0; }
+
+ // Add a single character to the builder. It is not allowed to add
+ // 0-characters; use the Finalize() method to terminate the string
+ // instead.
+ void AddCharacter(char c) {
+ ASSERT(c != '\0');
+ ASSERT(!is_finalized() && position_ < buffer_.length());
+ buffer_[position_++] = c;
+ }
+
+ // Add an entire string to the builder. Uses strlen() internally to
+ // compute the length of the input string.
+ void AddString(const char* s) {
+ AddSubstring(s, StrLength(s));
+ }
+
+ // Add the first 'n' characters of the given string 's' to the
+ // builder. The input string must have enough characters.
+ void AddSubstring(const char* s, int n) {
+ ASSERT(!is_finalized() && position_ + n < buffer_.length());
+ ASSERT(static_cast<size_t>(n) <= strlen(s));
+ memcpy(&buffer_[position_], s, n * kCharSize);
+ position_ += n;
+ }
+
+
+ // Add character padding to the builder. If count is non-positive,
+ // nothing is added to the builder.
+ void AddPadding(char c, int count) {
+ for (int i = 0; i < count; i++) {
+ AddCharacter(c);
+ }
+ }
+
+ // Finalize the string by 0-terminating it and returning the buffer.
+ char* Finalize() {
+ ASSERT(!is_finalized() && position_ < buffer_.length());
+ buffer_[position_] = '\0';
+ // Make sure nobody managed to add a 0-character to the
+ // buffer while building the string.
+ ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
+ position_ = -1;
+ ASSERT(is_finalized());
+ return buffer_.start();
+ }
+
+ private:
+ Vector<char> buffer_;
+ int position_;
+
+ bool is_finalized() const { return position_ < 0; }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+ };
+
+ // The type-based aliasing rule allows the compiler to assume that pointers of
+ // different types (for some definition of different) never alias each other.
+ // Thus the following code does not work:
+ //
+ // float f = foo();
+ // int fbits = *(int*)(&f);
+ //
+ // The compiler 'knows' that the int pointer can't refer to f since the types
+ // don't match, so the compiler may cache f in a register, leaving random data
+ // in fbits. Using C++ style casts makes no difference, however a pointer to
+ // char data is assumed to alias any other pointer. This is the 'memcpy
+ // exception'.
+ //
+ // Bit_cast uses the memcpy exception to move the bits from a variable of one
+ // type of a variable of another type. Of course the end result is likely to
+ // be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
+ // will completely optimize BitCast away.
+ //
+ // There is an additional use for BitCast.
+ // Recent gccs will warn when they see casts that may result in breakage due to
+ // the type-based aliasing rule. If you have checked that there is no breakage
+ // you can use BitCast to cast one pointer type to another. This confuses gcc
+ // enough that it can no longer see that you have cast one pointer type to
+ // another thus avoiding the warning.
+ template <class Dest, class Source>
+ inline Dest BitCast(const Source& source) {
+ // Compile time assertion: sizeof(Dest) == sizeof(Source)
+ // A compile error here means your Dest and Source have different sizes.
+ typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+ }
+
+ template <class Dest, class Source>
+ inline Dest BitCast(Source* source) {
+ return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
+ }
+
+} // namespace double_conversion
+
+} // namespace WTF
+
+#endif // DOUBLE_CONVERSION_UTILS_H_
diff --git a/Source/JavaScriptCore/wtf/efl/MainThreadEfl.cpp b/Source/JavaScriptCore/wtf/efl/MainThreadEfl.cpp
new file mode 100644
index 000000000..53adcb2b1
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/efl/MainThreadEfl.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+static OwnPtr<Ecore_Pipe>& pipeObject()
+{
+ DEFINE_STATIC_LOCAL(OwnPtr<Ecore_Pipe>, pipeObject, ());
+ return pipeObject;
+}
+
+static void monitorDispatchFunctions(void*, void*, unsigned int)
+{
+ dispatchFunctionsFromMainThread();
+}
+
+void initializeMainThreadPlatform()
+{
+ pipeObject() = adoptPtr(ecore_pipe_add(monitorDispatchFunctions, 0));
+}
+
+void scheduleDispatchFunctionsOnMainThread()
+{
+ ecore_pipe_write(pipeObject().get(), "", 0);
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp b/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp
new file mode 100644
index 000000000..7ec517029
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/efl/OwnPtrEfl.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 ProFUSION embedded systems
+ * Copyright (C) 2011 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.
+ *
+ * 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 "OwnPtr.h"
+
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Evas.h>
+
+namespace WTF {
+
+void deleteOwnedPtr(Ecore_Evas* ptr)
+{
+ if (ptr)
+ ecore_evas_free(ptr);
+}
+
+void deleteOwnedPtr(Evas_Object* ptr)
+{
+ evas_object_del(ptr);
+}
+
+void deleteOwnedPtr(Ecore_Pipe* ptr)
+{
+ if (ptr)
+ ecore_pipe_del(ptr);
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp
new file mode 100644
index 000000000..50c7b9ffc
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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
+ */
+
+#include "config.h"
+#include "GOwnPtr.h"
+
+#if ENABLE(GLIB_SUPPORT)
+
+#include <gio/gio.h>
+#include <glib.h>
+
+namespace WTF {
+
+template <> void freeOwnedGPtr<GError>(GError* ptr)
+{
+ if (ptr)
+ g_error_free(ptr);
+}
+
+template <> void freeOwnedGPtr<GList>(GList* ptr)
+{
+ g_list_free(ptr);
+}
+
+template <> void freeOwnedGPtr<GPatternSpec>(GPatternSpec* ptr)
+{
+ if (ptr)
+ g_pattern_spec_free(ptr);
+}
+
+template <> void freeOwnedGPtr<GDir>(GDir* ptr)
+{
+ if (ptr)
+ g_dir_close(ptr);
+}
+
+} // namespace WTF
+
+#endif // ENABLE(GLIB_SUPPORT)
diff --git a/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h
new file mode 100644
index 000000000..9ff85c5a4
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GOwnPtr.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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 GOwnPtr_h
+#define GOwnPtr_h
+
+#if ENABLE(GLIB_SUPPORT)
+
+#include <algorithm>
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+extern "C" void g_free(void*);
+
+namespace WTF {
+
+template <typename T> inline void freeOwnedGPtr(T* ptr);
+template<> void freeOwnedGPtr<GError>(GError*);
+template<> void freeOwnedGPtr<GList>(GList*);
+template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*);
+template<> void freeOwnedGPtr<GDir>(GDir*);
+
+template <typename T> class GOwnPtr {
+ WTF_MAKE_NONCOPYABLE(GOwnPtr);
+public:
+ explicit GOwnPtr(T* ptr = 0) : m_ptr(ptr) { }
+ ~GOwnPtr() { freeOwnedGPtr(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);
+ freeOwnedGPtr(m_ptr);
+ m_ptr = ptr;
+ }
+
+ void clear()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ freeOwnedGPtr(ptr);
+ }
+
+ 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* GOwnPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &GOwnPtr::m_ptr : 0; }
+
+ void swap(GOwnPtr& o) { std::swap(m_ptr, o.m_ptr); }
+
+private:
+ T* m_ptr;
+};
+
+template <typename T> inline void swap(GOwnPtr<T>& a, GOwnPtr<T>& b)
+{
+ a.swap(b);
+}
+
+template <typename T, typename U> inline bool operator==(const GOwnPtr<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template <typename T, typename U> inline bool operator==(T* a, const GOwnPtr<U>& b)
+{
+ return a == b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const GOwnPtr<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template <typename T, typename U> inline bool operator!=(T* a, const GOwnPtr<U>& b)
+{
+ return a != b.get();
+}
+
+template <typename T> inline typename GOwnPtr<T>::PtrType getPtr(const GOwnPtr<T>& p)
+{
+ return p.get();
+}
+
+template <typename T> inline void freeOwnedGPtr(T* ptr)
+{
+ g_free(ptr);
+}
+
+} // namespace WTF
+
+using WTF::GOwnPtr;
+
+#endif // ENABLE(GLIB_SUPPORT)
+
+#endif // GOwnPtr_h
+
diff --git a/Source/JavaScriptCore/wtf/gobject/GRefPtr.cpp b/Source/JavaScriptCore/wtf/gobject/GRefPtr.cpp
new file mode 100644
index 000000000..1cd22c532
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GRefPtr.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 Martin Robinson
+ *
+ * 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
+ */
+
+#include "config.h"
+#include "GRefPtr.h"
+
+#if ENABLE(GLIB_SUPPORT)
+
+#include <glib.h>
+
+namespace WTF {
+
+template <> GHashTable* refGPtr(GHashTable* ptr)
+{
+ if (ptr)
+ g_hash_table_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GHashTable* ptr)
+{
+ g_hash_table_unref(ptr);
+}
+
+#if GLIB_CHECK_VERSION(2, 24, 0)
+template <> GVariant* refGPtr(GVariant* ptr)
+{
+ if (ptr)
+ g_variant_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(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* refGPtr(GVariant* ptr)
+{
+ return ptr;
+}
+
+template <> void derefGPtr(GVariant* ptr)
+{
+}
+
+#endif
+
+template <> GSource* refGPtr(GSource* ptr)
+{
+ if (ptr)
+ g_source_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GSource* ptr)
+{
+ if (ptr)
+ g_source_unref(ptr);
+}
+
+} // namespace WTF
+
+#endif // ENABLE(GLIB_SUPPORT)
diff --git a/Source/JavaScriptCore/wtf/gobject/GRefPtr.h b/Source/JavaScriptCore/wtf/gobject/GRefPtr.h
new file mode 100644
index 000000000..10ebf0753
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GRefPtr.h
@@ -0,0 +1,229 @@
+/*
+ * 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 "GRefPtr.h"
+#include "RefPtr.h"
+#include <algorithm>
+
+extern "C" void g_object_unref(gpointer);
+extern "C" gpointer g_object_ref_sink(gpointer);
+
+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 <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()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ if (ptr)
+ derefGPtr(ptr);
+ }
+
+ T* leakRef() WARN_UNUSED_RETURN
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ GRefPtr(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* 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 <> GHashTable* refGPtr(GHashTable* ptr);
+template <> void derefGPtr(GHashTable* ptr);
+template <> GVariant* refGPtr(GVariant* ptr);
+template <> void derefGPtr(GVariant* ptr);
+template <> GSource* refGPtr(GSource* ptr);
+template <> void derefGPtr(GSource* ptr);
+
+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::adoptGRef;
+
+#endif // ENABLE(GLIB_SUPPORT)
+
+#endif // WTF_GRefPtr_h
diff --git a/Source/JavaScriptCore/wtf/gobject/GTypedefs.h b/Source/JavaScriptCore/wtf/gobject/GTypedefs.h
new file mode 100644
index 000000000..66cedd6d2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GTypedefs.h
@@ -0,0 +1,95 @@
+/*
+ * 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 _GDir GDir;
+typedef struct _GdkAtom* GdkAtom;
+typedef struct _GdkCursor GdkCursor;
+typedef struct _GdkDragContext GdkDragContext;
+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 _GPatternSpec GPatternSpec;
+typedef struct _GPollableOutputStream GPollableOutputStream;
+typedef struct _GSocketClient GSocketClient;
+typedef struct _GSocketConnection GSocketConnection;
+typedef struct _GSource GSource;
+typedef struct _GVariant GVariant;
+typedef union _GdkEvent GdkEvent;
+
+#if USE(CAIRO)
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo_rectangle_int cairo_rectangle_int_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;
+typedef struct _GdkDrawable GdkWindow;
+#else
+typedef struct _GdkWindow GdkWindow;
+typedef struct _GtkStyleContext GtkStyleContext;
+#endif
+
+#endif
+
+#endif
+#endif /* GtkTypedefs_h */
diff --git a/Source/JavaScriptCore/wtf/gobject/GlibUtilities.cpp b/Source/JavaScriptCore/wtf/gobject/GlibUtilities.cpp
new file mode 100644
index 000000000..6fcd806eb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GlibUtilities.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "GlibUtilities.h"
+
+#include <limits.h>
+#include <unistd.h>
+
+#if OS(LINUX)
+CString getCurrentExecutablePath()
+{
+ static char readLinkBuffer[PATH_MAX];
+ ssize_t result = readlink("/proc/self/exe", readLinkBuffer, PATH_MAX);
+ if (result == -1)
+ return CString();
+ return CString(readLinkBuffer, result);
+}
+#elif OS(UNIX)
+CString getCurrentExecutablePath()
+{
+ static char readLinkBuffer[PATH_MAX];
+ ssize_t result = readlink("/proc/curproc/file", readLinkBuffer, PATH_MAX);
+ if (result == -1)
+ return CString();
+ return CString(readLinkBuffer, result);
+}
+#endif
diff --git a/Source/JavaScriptCore/wtf/gobject/GlibUtilities.h b/Source/JavaScriptCore/wtf/gobject/GlibUtilities.h
new file mode 100644
index 000000000..5577bf58e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gobject/GlibUtilities.h
@@ -0,0 +1,28 @@
+/*
+ * 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 GlibUtilities_h
+#define GlibUtilities_h
+
+#include "Assertions.h"
+#include "CString.h"
+
+CString getCurrentExecutablePath();
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp b/Source/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp
new file mode 100644
index 000000000..7624247b6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007, 2008 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 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 <glib.h>
+
+namespace WTF {
+
+void initializeMainThreadPlatform()
+{
+}
+
+static gboolean timeoutFired(gpointer)
+{
+ dispatchFunctionsFromMainThread();
+ return FALSE;
+}
+
+void scheduleDispatchFunctionsOnMainThread()
+{
+ g_timeout_add(0, timeoutFired, 0);
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/mac/MainThreadMac.mm b/Source/JavaScriptCore/wtf/mac/MainThreadMac.mm
new file mode 100644
index 000000000..fbc625032
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/mac/MainThreadMac.mm
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2007, 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.
+ */
+
+#import "config.h"
+#import "MainThread.h"
+
+#import <CoreFoundation/CoreFoundation.h>
+#import <Foundation/NSThread.h>
+#import <stdio.h>
+#import <wtf/Assertions.h>
+#import <wtf/HashSet.h>
+#import <wtf/Threading.h>
+#import <wtf/ThreadSpecific.h>
+
+@interface JSWTFMainThreadCaller : NSObject {
+}
+- (void)call;
+@end
+
+@implementation JSWTFMainThreadCaller
+
+- (void)call
+{
+ WTF::dispatchFunctionsFromMainThread();
+}
+
+@end // implementation JSWTFMainThreadCaller
+
+namespace WTF {
+
+static JSWTFMainThreadCaller* staticMainThreadCaller;
+static bool isTimerPosted; // This is only accessed on the 'main' thread.
+static bool mainThreadEstablishedAsPthreadMain;
+static pthread_t mainThreadPthread;
+static NSThread* mainThreadNSThread;
+
+#if ENABLE(PARALLEL_GC)
+static ThreadSpecific<bool>* isGCThread;
+
+static void initializeGCThreads()
+{
+ isGCThread = new ThreadSpecific<bool>();
+}
+#else
+static void initializeGCThreads() { }
+#endif
+
+void initializeMainThreadPlatform()
+{
+ ASSERT(!staticMainThreadCaller);
+ staticMainThreadCaller = [[JSWTFMainThreadCaller alloc] init];
+
+ mainThreadEstablishedAsPthreadMain = false;
+ mainThreadPthread = pthread_self();
+ mainThreadNSThread = [[NSThread currentThread] retain];
+
+ initializeGCThreads();
+}
+
+void initializeMainThreadToProcessMainThreadPlatform()
+{
+ if (!pthread_main_np())
+ NSLog(@"WebKit Threading Violation - initial use of WebKit from a secondary thread.");
+
+ ASSERT(!staticMainThreadCaller);
+ staticMainThreadCaller = [[JSWTFMainThreadCaller alloc] init];
+
+ mainThreadEstablishedAsPthreadMain = true;
+ mainThreadPthread = 0;
+ mainThreadNSThread = nil;
+
+ initializeGCThreads();
+}
+
+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 (isMainThread()) {
+ postTimer();
+ return;
+ }
+
+ if (mainThreadEstablishedAsPthreadMain) {
+ ASSERT(!mainThreadNSThread);
+ [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO];
+ return;
+ }
+
+ ASSERT(mainThreadNSThread);
+ [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO];
+}
+
+bool isMainThread()
+{
+ if (mainThreadEstablishedAsPthreadMain) {
+ ASSERT(!mainThreadPthread);
+ return pthread_main_np();
+ }
+
+ ASSERT(mainThreadPthread);
+ return pthread_equal(pthread_self(), mainThreadPthread);
+}
+
+#if ENABLE(PARALLEL_GC)
+void registerGCThread()
+{
+ if (!isGCThread) {
+ // This happens if we're running in a process that doesn't care about
+ // MainThread.
+ return;
+ }
+
+ **isGCThread = true;
+}
+
+bool isMainThreadOrGCThread()
+{
+ if (isGCThread->isSet() && **isGCThread)
+ return true;
+
+ return isMainThread();
+}
+#else
+// This is necessary because JavaScriptCore.exp doesn't support preprocessor macros.
+bool isMainThreadOrGCThread()
+{
+ return isMainThread();
+}
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/qt/MainThreadQt.cpp b/Source/JavaScriptCore/wtf/qt/MainThreadQt.cpp
new file mode 100644
index 000000000..606a7190e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/qt/MainThreadQt.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 Staikos Computing Services Inc.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * 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.
+ */
+
+#include "config.h"
+#include "MainThread.h"
+
+#include <QCoreApplication>
+#include <QEvent>
+#include <QObject>
+#include <QThread>
+
+namespace WTF {
+
+static int s_mainThreadInvokerEventType;
+
+class MainThreadInvoker : public QObject {
+ Q_OBJECT
+public:
+ MainThreadInvoker();
+ virtual bool event(QEvent*);
+};
+
+MainThreadInvoker::MainThreadInvoker()
+{
+ s_mainThreadInvokerEventType = QEvent::registerEventType();
+}
+
+bool MainThreadInvoker::event(QEvent* e)
+{
+ if (e->type() != s_mainThreadInvokerEventType)
+ return QObject::event(e);
+
+ dispatchFunctionsFromMainThread();
+ return true;
+}
+
+Q_GLOBAL_STATIC(MainThreadInvoker, webkit_main_thread_invoker)
+
+void initializeMainThreadPlatform()
+{
+ webkit_main_thread_invoker();
+}
+
+void scheduleDispatchFunctionsOnMainThread()
+{
+ QCoreApplication::postEvent(webkit_main_thread_invoker(), new QEvent(static_cast<QEvent::Type>(s_mainThreadInvokerEventType)));
+}
+
+} // namespace WTF
+
+#include "MainThreadQt.moc"
diff --git a/Source/JavaScriptCore/wtf/qt/StringQt.cpp b/Source/JavaScriptCore/wtf/qt/StringQt.cpp
new file mode 100644
index 000000000..16dd439e3
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/qt/UtilsQt.h b/Source/JavaScriptCore/wtf/qt/UtilsQt.h
new file mode 100644
index 000000000..74067a8ee
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/qt/UtilsQt.h
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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_UtilsQt_h
+#define WTF_UtilsQt_h
+
+#include <QString>
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+#include <QTextDocument>
+#endif
+
+inline QString escapeHtml(const QString& string)
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ return string.toHtmlEscaped();
+#else
+ return Qt::escape(string);
+#endif
+}
+
+#endif // WTF_UtilsQt_h
diff --git a/Source/JavaScriptCore/wtf/qt/compat/QGuiApplication b/Source/JavaScriptCore/wtf/qt/compat/QGuiApplication
new file mode 100644
index 000000000..0337e2526
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/qt/compat/QGuiApplication
@@ -0,0 +1 @@
+#include "qguiapplication.h"
diff --git a/Source/JavaScriptCore/wtf/qt/compat/qguiapplication.h b/Source/JavaScriptCore/wtf/qt/compat/qguiapplication.h
new file mode 100644
index 000000000..2a2fc23cb
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/qt/compat/qguiapplication.h
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 qguiapplication_h
+#define qguiapplication_h
+
+#include <QApplication>
+
+struct QGuiApplication : public QApplication
+{
+ // Style hints in Qt 5 contain stuff that just used to be in QApplication in Qt 4, hence
+ // this hack.
+ static QApplication* styleHints()
+ {
+ return qApp;
+ }
+};
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/text/ASCIIFastPath.h b/Source/JavaScriptCore/wtf/text/ASCIIFastPath.h
new file mode 100644
index 000000000..ace1a687d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/ASCIIFastPath.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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 ASCIIFastPath_h
+#define ASCIIFastPath_h
+
+#include <stdint.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WTF {
+
+// Assuming that a pointer is the size of a "machine word", then
+// uintptr_t is an integer type that is also a machine word.
+typedef uintptr_t MachineWord;
+const uintptr_t machineWordAlignmentMask = sizeof(MachineWord) - 1;
+
+inline bool isAlignedToMachineWord(const void* pointer)
+{
+ return !(reinterpret_cast<uintptr_t>(pointer) & machineWordAlignmentMask);
+}
+
+template<typename T> inline T* alignToMachineWord(T* pointer)
+{
+ return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(pointer) & ~machineWordAlignmentMask);
+}
+
+template<size_t size, typename CharacterType> struct NonASCIIMask;
+template<> struct NonASCIIMask<4, UChar> {
+ static inline uint32_t value() { return 0xFF80FF80U; }
+};
+template<> struct NonASCIIMask<4, LChar> {
+ static inline uint32_t value() { return 0x80808080U; }
+};
+template<> struct NonASCIIMask<8, UChar> {
+ static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
+};
+template<> struct NonASCIIMask<8, LChar> {
+ static inline uint64_t value() { return 0x8080808080808080ULL; }
+};
+
+
+template<typename CharacterType>
+inline bool isAllASCII(MachineWord word)
+{
+ return !(word & NonASCIIMask<sizeof(MachineWord), CharacterType>::value());
+}
+
+// Note: This function assume the input is likely all ASCII, and
+// does not leave early if it is not the case.
+template<typename CharacterType>
+inline bool charactersAreAllASCII(const CharacterType* characters, size_t length)
+{
+ MachineWord allCharBits = 0;
+ const CharacterType* end = characters + length;
+
+ // Prologue: align the input.
+ while (!isAlignedToMachineWord(characters) && characters != end) {
+ allCharBits |= *characters;
+ ++characters;
+ }
+
+ // Compare the values of CPU word size.
+ const CharacterType* wordEnd = alignToMachineWord(end);
+ const size_t loopIncrement = sizeof(MachineWord) / sizeof(CharacterType);
+ while (characters < wordEnd) {
+ allCharBits |= *(reinterpret_cast<const MachineWord*>(characters));
+ characters += loopIncrement;
+ }
+
+ // Process the remaining bytes.
+ while (characters != end) {
+ allCharBits |= *characters;
+ ++characters;
+ }
+
+ MachineWord nonASCIIBitMask = NonASCIIMask<sizeof(MachineWord), CharacterType>::value();
+ return !(allCharBits & nonASCIIBitMask);
+}
+
+
+} // namespace WTF
+
+#endif // ASCIIFastPath_h
diff --git a/Source/JavaScriptCore/wtf/text/AtomicString.cpp b/Source/JavaScriptCore/wtf/text/AtomicString.cpp
new file mode 100644
index 000000000..966879827
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/AtomicString.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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.
+ *
+ */
+
+#include "config.h"
+
+#include "AtomicString.h"
+
+#include "StringHash.h"
+#include <wtf/HashSet.h>
+#include <wtf/Threading.h>
+#include <wtf/WTFThreadData.h>
+#include <wtf/unicode/UTF8.h>
+
+namespace WTF {
+
+using namespace Unicode;
+
+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();
+}
+
+template<typename T, typename HashTranslator>
+static inline PassRefPtr<StringImpl> addToStringTable(const T& value)
+{
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<T, HashTranslator>(value);
+
+ // 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;
+}
+
+struct CStringTranslator {
+ static unsigned hash(const LChar* c)
+ {
+ return StringHasher::computeHash(c);
+ }
+
+ static inline bool equal(StringImpl* r, const LChar* s)
+ {
+ return WTF::equal(r, s);
+ }
+
+ static void translate(StringImpl*& location, const LChar* const& c, unsigned hash)
+ {
+ location = StringImpl::create(c).leakRef();
+ location->setHash(hash);
+ location->setIsAtomic(true);
+ }
+};
+
+PassRefPtr<StringImpl> AtomicString::add(const LChar* c)
+{
+ if (!c)
+ return 0;
+ if (!*c)
+ return StringImpl::empty();
+
+ return addToStringTable<const LChar*, CStringTranslator>(c);
+}
+
+struct UCharBuffer {
+ const UChar* s;
+ unsigned length;
+};
+
+struct UCharBufferTranslator {
+ static unsigned hash(const UCharBuffer& buf)
+ {
+ return StringHasher::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 == StringHasher::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);
+ }
+};
+
+struct HashAndUTF8Characters {
+ unsigned hash;
+ const char* characters;
+ unsigned length;
+ unsigned utf16Length;
+};
+
+struct HashAndUTF8CharactersTranslator {
+ static unsigned hash(const HashAndUTF8Characters& buffer)
+ {
+ return buffer.hash;
+ }
+
+ static bool equal(StringImpl* const& string, const HashAndUTF8Characters& buffer)
+ {
+ if (buffer.utf16Length != string->length())
+ return false;
+
+ const UChar* stringCharacters = string->characters();
+
+ // If buffer contains only ASCII characters UTF-8 and UTF16 length are the same.
+ if (buffer.utf16Length != buffer.length)
+ return equalUTF16WithUTF8(stringCharacters, stringCharacters + string->length(), buffer.characters, buffer.characters + buffer.length);
+
+ for (unsigned i = 0; i < buffer.length; ++i) {
+ ASSERT(isASCII(buffer.characters[i]));
+ if (stringCharacters[i] != buffer.characters[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ static void translate(StringImpl*& location, const HashAndUTF8Characters& buffer, unsigned hash)
+ {
+ UChar* target;
+ location = StringImpl::createUninitialized(buffer.utf16Length, target).leakRef();
+
+ const char* source = buffer.characters;
+ if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target + buffer.utf16Length) != conversionOK)
+ ASSERT_NOT_REACHED();
+
+ location->setHash(hash);
+ location->setIsAtomic(true);
+ }
+};
+
+PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length)
+{
+ if (!s)
+ return 0;
+
+ if (!length)
+ return StringImpl::empty();
+
+ UCharBuffer buffer = { s, length };
+ return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
+}
+
+PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsigned existingHash)
+{
+ ASSERT(s);
+ ASSERT(existingHash);
+
+ if (!length)
+ return StringImpl::empty();
+
+ HashAndCharacters buffer = { existingHash, s, length };
+ return addToStringTable<HashAndCharacters, HashAndCharactersTranslator>(buffer);
+}
+
+PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
+{
+ if (!s)
+ return 0;
+
+ int length = 0;
+ while (s[length] != UChar(0))
+ length++;
+
+ if (!length)
+ return StringImpl::empty();
+
+ UCharBuffer buffer = { s, length };
+ return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
+}
+
+PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
+{
+ if (!r || r->isAtomic())
+ return r;
+
+ if (!r->length())
+ 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)
+ 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);
+}
+
+AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd)
+{
+ HashAndUTF8Characters buffer;
+ buffer.characters = charactersStart;
+ buffer.hash = calculateStringHashAndLengthFromUTF8(charactersStart, charactersEnd, buffer.length, buffer.utf16Length);
+
+ if (!buffer.hash)
+ return nullAtom;
+
+ AtomicString atomicString;
+ atomicString.m_string = addToStringTable<HashAndUTF8Characters, HashAndUTF8CharactersTranslator>(buffer);
+ return atomicString;
+}
+
+#ifndef NDEBUG
+void AtomicString::show() const
+{
+ m_string.show();
+}
+#endif
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/text/AtomicString.h b/Source/JavaScriptCore/wtf/text/AtomicString.h
new file mode 100644
index 000000000..43b38d179
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/AtomicString.h
@@ -0,0 +1,215 @@
+/*
+ * 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 LChar* s) : m_string(add(s)) { }
+ 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 LChar* 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 LChar* 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 USE(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
+
+ // AtomicString::fromUTF8 will return a null string if
+ // the input data contains invalid UTF-8 sequences.
+ static AtomicString fromUTF8(const char*, size_t);
+ static AtomicString fromUTF8(const char*);
+
+#ifndef NDEBUG
+ void show() const;
+#endif
+private:
+ String m_string;
+
+ static PassRefPtr<StringImpl> add(const LChar*);
+ ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s) { return add(reinterpret_cast<const LChar*>(s)); };
+ static PassRefPtr<StringImpl> add(const UChar*, unsigned length);
+ ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const char*>(s), 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*);
+ static AtomicString fromUTF8Internal(const char*, const char*);
+};
+
+inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
+bool operator==(const AtomicString&, const LChar*);
+inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool operator==(const AtomicString& a, const Vector<UChar>& b) { return a.impl() && equal(a.impl(), b.data(), b.size()); }
+inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); }
+inline bool operator==(const LChar* 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 LChar* b) { return !(a == b); }
+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 LChar* 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 LChar* b) { return equalIgnoringCase(a.impl(), b); }
+inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); }
+inline bool equalIgnoringCase(const LChar* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(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 WTF_EXPORTDATA AtomicString nullAtom;
+extern const WTF_EXPORTDATA AtomicString emptyAtom;
+extern const WTF_EXPORTDATA AtomicString textAtom;
+extern const WTF_EXPORTDATA AtomicString commentAtom;
+extern const WTF_EXPORTDATA AtomicString starAtom;
+extern const WTF_EXPORTDATA AtomicString xmlAtom;
+extern const WTF_EXPORTDATA AtomicString xmlnsAtom;
+
+inline AtomicString AtomicString::fromUTF8(const char* characters, size_t length)
+{
+ if (!characters)
+ return nullAtom;
+ if (!length)
+ return emptyAtom;
+ return fromUTF8Internal(characters, characters + length);
+}
+
+inline AtomicString AtomicString::fromUTF8(const char* characters)
+{
+ if (!characters)
+ return nullAtom;
+ if (!*characters)
+ return emptyAtom;
+ return fromUTF8Internal(characters, 0);
+}
+#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
+
+#include "StringConcatenate.h"
+#endif // AtomicString_h
diff --git a/Source/JavaScriptCore/wtf/text/AtomicStringHash.h b/Source/JavaScriptCore/wtf/text/AtomicStringHash.h
new file mode 100644
index 000000000..6130d9493
--- /dev/null
+++ b/Source/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 (NotNull, &slot) WTF::AtomicString(HashTableDeletedValue); }
+ static bool isDeletedValue(const WTF::AtomicString& slot) { return slot.isHashTableDeletedValue(); }
+ };
+
+}
+
+using WTF::AtomicStringHash;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/text/AtomicStringImpl.h b/Source/JavaScriptCore/wtf/text/AtomicStringImpl.h
new file mode 100644
index 000000000..3f0c37606
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/text/CString.cpp b/Source/JavaScriptCore/wtf/text/CString.cpp
new file mode 100644
index 000000000..981d77a1d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/CString.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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;
+
+ // We need to be sure we can add 1 to length without overflowing.
+ // Since the passed-in length is the length of an actual existing
+ // string, and we know the string doesn't occupy the entire address
+ // space, we can assert here and there's no need for a runtime check.
+ ASSERT(length < numeric_limits<size_t>::max());
+
+ 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/Source/JavaScriptCore/wtf/text/CString.h b/Source/JavaScriptCore/wtf/text/CString.h
new file mode 100644
index 000000000..343a7a525
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/wtf/text/StringBuffer.h b/Source/JavaScriptCore/wtf/text/StringBuffer.h
new file mode 100644
index 000000000..739260d27
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringBuffer.h
@@ -0,0 +1,87 @@
+/*
+ * 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/unicode/Unicode.h>
+#include <limits>
+
+namespace WTF {
+
+template <typename CharType>
+class StringBuffer {
+ WTF_MAKE_NONCOPYABLE(StringBuffer);
+public:
+ explicit StringBuffer(unsigned length)
+ : m_length(length)
+ {
+ if (m_length > std::numeric_limits<unsigned>::max() / sizeof(CharType))
+ CRASH();
+ m_data = static_cast<CharType*>(fastMalloc(m_length * sizeof(CharType)));
+ }
+
+ ~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; }
+ CharType* characters() { return m_data; }
+
+ UChar& operator[](unsigned i) { ASSERT(i < m_length); return m_data[i]; }
+
+ CharType* release() { CharType* data = m_data; m_data = 0; return data; }
+
+private:
+ unsigned m_length;
+ CharType* m_data;
+};
+
+} // namespace WTF
+
+using WTF::StringBuffer;
+
+#endif // StringBuffer_h
diff --git a/Source/JavaScriptCore/wtf/text/StringBuilder.cpp b/Source/JavaScriptCore/wtf/text/StringBuilder.cpp
new file mode 100644
index 000000000..6d3c310e6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringBuilder.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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 {
+
+static const unsigned minimumCapacity = 16;
+
+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);
+
+ if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length)
+ m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length);
+
+ m_valid16BitShadowLength = 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()) {
+ if (m_buffer->is8Bit())
+ allocateBuffer(m_buffer->characters8(), m_buffer->length());
+ else
+ allocateBuffer(m_buffer->characters16(), 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);
+}
+
+// Allocate a new 8 bit 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 LChar* currentCharacters, unsigned requiredLength)
+{
+ ASSERT(m_is8Bit);
+ // 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_bufferCharacters8);
+ memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow.
+
+ // Update the builder state.
+ m_buffer = buffer.release();
+ m_string = String();
+}
+
+// Allocate a new 16 bit 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)
+{
+ ASSERT(!m_is8Bit);
+ // 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_bufferCharacters16);
+ memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
+
+ // Update the builder state.
+ m_buffer = buffer.release();
+ m_string = String();
+}
+
+// Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come
+// from either m_string or m_buffer, neither will be reassigned until the copy has completed).
+void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength)
+{
+ ASSERT(m_is8Bit);
+ // 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_bufferCharacters16);
+ for (unsigned i = 0; i < m_length; i++)
+ m_bufferCharacters16[i] = currentCharacters[i];
+
+ m_is8Bit = false;
+
+ // Update the builder state.
+ m_buffer = buffer.release();
+ m_string = String();
+}
+
+template <>
+void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength)
+{
+ // If the buffer has only one ref (by this StringBuilder), reallocate it,
+ // otherwise fall back to "allocate and copy" method.
+ m_string = String();
+
+ ASSERT(m_is8Bit);
+ ASSERT(m_buffer->is8Bit());
+
+ if (m_buffer->hasOneRef())
+ m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters8);
+ else
+ allocateBuffer(m_buffer->characters8(), requiredLength);
+}
+
+template <>
+void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength)
+{
+ // If the buffer has only one ref (by this StringBuilder), reallocate it,
+ // otherwise fall back to "allocate and copy" method.
+ m_string = String();
+
+ if (m_buffer->is8Bit())
+ allocateBufferUpConvert(m_buffer->characters8(), requiredLength);
+ else if (m_buffer->hasOneRef())
+ m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters16);
+ else
+ allocateBuffer(m_buffer->characters16(), requiredLength);
+}
+
+void StringBuilder::reserveCapacity(unsigned newCapacity)
+{
+ if (m_buffer) {
+ // If there is already a buffer, then grow if necessary.
+ if (newCapacity > m_buffer->length()) {
+ if (m_buffer->is8Bit())
+ reallocateBuffer<LChar>(newCapacity);
+ else
+ reallocateBuffer<UChar>(newCapacity);
+ }
+ } else {
+ // Grow the string, if necessary.
+ if (newCapacity > m_length) {
+ if (!m_length) {
+ LChar* nullPlaceholder = 0;
+ allocateBuffer(nullPlaceholder, newCapacity);
+ } else if (m_string.is8Bit())
+ allocateBuffer(m_string.characters8(), newCapacity);
+ else
+ allocateBuffer(m_string.characters16(), newCapacity);
+ }
+ }
+}
+
+// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
+// return a pointer to the newly allocated storage.
+template <typename CharType>
+ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length)
+{
+ ASSERT(length);
+
+ // Calculate the new size of the builder after appending.
+ unsigned requiredLength = length + m_length;
+ if (requiredLength < length)
+ CRASH();
+
+ if ((m_buffer) && (requiredLength <= m_buffer->length())) {
+ // If the buffer is valid it must be at least as long as the current builder contents!
+ ASSERT(m_buffer->length() >= m_length);
+ unsigned currentLength = m_length;
+ m_string = String();
+ m_length = requiredLength;
+ return getBufferCharacters<CharType>() + currentLength;
+ }
+
+ return appendUninitializedSlow<CharType>(requiredLength);
+}
+
+// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
+// return a pointer to the newly allocated storage.
+template <typename CharType>
+CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
+{
+ ASSERT(requiredLength);
+
+ 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);
+
+ reallocateBuffer<CharType>(std::max(requiredLength, std::max(minimumCapacity, m_buffer->length() * 2)));
+ } else {
+ ASSERT(m_string.length() == m_length);
+ allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, std::max(requiredLength, std::max(minimumCapacity, m_length * 2)));
+ }
+
+ CharType* result = getBufferCharacters<CharType>() + m_length;
+ m_length = requiredLength;
+ return result;
+}
+
+void StringBuilder::append(const UChar* characters, unsigned length)
+{
+ if (!length)
+ return;
+
+ ASSERT(characters);
+
+ if (m_is8Bit) {
+ // Calculate 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);
+
+ allocateBufferUpConvert(m_buffer->characters8(), requiredLength);
+ } else {
+ ASSERT(m_string.length() == m_length);
+ allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), std::max(requiredLength, std::max(minimumCapacity, m_length * 2)));
+ }
+
+ memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));
+ m_length = requiredLength;
+ } else
+ memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar));
+}
+
+void StringBuilder::append(const LChar* characters, unsigned length)
+{
+ if (!length)
+ return;
+ ASSERT(characters);
+
+ if (m_is8Bit) {
+ LChar* dest = appendUninitialized<LChar>(length);
+ if (length > 8)
+ memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar));
+ else {
+ const LChar* end = characters + length;
+ while (characters < end)
+ *(dest++) = *(characters++);
+ }
+ } else {
+ UChar* dest = appendUninitialized<UChar>(length);
+ const LChar* end = characters + length;
+ while (characters < end)
+ *(dest++) = *(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))) {
+ if (m_is8Bit)
+ reallocateBuffer<LChar>(m_length);
+ else
+ reallocateBuffer<UChar>(m_length);
+ m_string = m_buffer;
+ m_buffer = 0;
+ }
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/text/StringBuilder.h b/Source/JavaScriptCore/wtf/text/StringBuilder.h
new file mode 100644
index 000000000..da1e8320d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringBuilder.h
@@ -0,0 +1,234 @@
+/*
+ * 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)
+ , m_is8Bit(true)
+ , m_valid16BitShadowLength(0)
+ , m_bufferCharacters8(0)
+ {
+ }
+
+ void append(const UChar*, unsigned);
+ void append(const LChar*, unsigned);
+
+ ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast<const LChar*>(characters), length); }
+
+ void append(const String& string)
+ {
+ if (!string.length())
+ return;
+
+ // 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();
+ m_is8Bit = m_string.is8Bit();
+ return;
+ }
+
+ if (string.is8Bit())
+ append(string.characters8(), string.length());
+ else
+ append(string.characters16(), string.length());
+ }
+
+ void append(const char* characters)
+ {
+ if (characters)
+ append(characters, strlen(characters));
+ }
+
+ void append(UChar c)
+ {
+ if (m_buffer && !m_is8Bit && m_length < m_buffer->length() && m_string.isNull())
+ m_bufferCharacters16[m_length++] = c;
+ else
+ append(&c, 1);
+ }
+
+ void append(LChar c)
+ {
+ if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
+ if (m_is8Bit)
+ m_bufferCharacters8[m_length++] = c;
+ else
+ m_bufferCharacters16[m_length++] = c;
+ } else
+ append(&c, 1);
+ }
+
+ void append(char c)
+ {
+ if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
+ if (m_is8Bit)
+ m_bufferCharacters8[m_length++] = (LChar)c;
+ else
+ m_bufferCharacters16[m_length++] = (LChar)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_is8Bit)
+ return characters8()[i];
+ return characters16()[i];
+ }
+
+ const LChar* characters8() const
+ {
+ ASSERT(m_is8Bit);
+ if (!m_length)
+ return 0;
+ if (!m_string.isNull())
+ return m_string.characters8();
+ ASSERT(m_buffer);
+ return m_buffer->characters8();
+ }
+
+ const UChar* characters16() const
+ {
+ ASSERT(!m_is8Bit);
+ if (!m_length)
+ return 0;
+ if (!m_string.isNull())
+ return m_string.characters16();
+ ASSERT(m_buffer);
+ return m_buffer->characters16();
+ }
+
+ const UChar* characters() const
+ {
+ if (!m_length)
+ return 0;
+ if (!m_string.isNull())
+ return m_string.characters();
+ ASSERT(m_buffer);
+ if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length)
+ m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length);
+
+ m_valid16BitShadowLength = m_length;
+
+ return m_buffer->characters();
+ }
+
+ void clear()
+ {
+ m_length = 0;
+ m_string = String();
+ m_buffer = 0;
+ m_bufferCharacters8 = 0;
+ m_is8Bit = true;
+ m_valid16BitShadowLength = 0;
+ }
+
+private:
+ void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
+ void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
+ void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
+ template <typename CharType>
+ void reallocateBuffer(unsigned requiredLength);
+ template <typename CharType>
+ ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
+ template <typename CharType>
+ CharType* appendUninitializedSlow(unsigned length);
+ template <typename CharType>
+ ALWAYS_INLINE CharType * getBufferCharacters();
+ void reifyString();
+
+ unsigned m_length;
+ String m_string;
+ RefPtr<StringImpl> m_buffer;
+ bool m_is8Bit;
+ mutable unsigned m_valid16BitShadowLength;
+ union {
+ LChar* m_bufferCharacters8;
+ UChar* m_bufferCharacters16;
+ };
+};
+
+template <>
+ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
+{
+ ASSERT(m_is8Bit);
+ return m_bufferCharacters8;
+}
+
+template <>
+ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
+{
+ ASSERT(!m_is8Bit);
+ return m_bufferCharacters16;
+}
+
+} // namespace WTF
+
+using WTF::StringBuilder;
+
+#endif // StringBuilder_h
diff --git a/Source/JavaScriptCore/wtf/text/StringConcatenate.h b/Source/JavaScriptCore/wtf/text/StringConcatenate.h
new file mode 100644
index 000000000..08d67dcf0
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringConcatenate.h
@@ -0,0 +1,964 @@
+/*
+ * 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
+
+#ifndef WTFString_h
+#include "AtomicString.h"
+#endif
+
+// This macro is helpful for testing how many intermediate Strings are created while evaluating an
+// expression containing operator+.
+#ifndef WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING
+#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() ((void)0)
+#endif
+
+namespace WTF {
+
+template<typename StringType>
+class StringTypeAdapter {
+};
+
+template<>
+class StringTypeAdapter<char> {
+public:
+ StringTypeAdapter<char>(char buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return 1; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ *destination = m_buffer;
+ }
+
+ void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+ unsigned char m_buffer;
+};
+
+template<>
+class StringTypeAdapter<LChar> {
+public:
+ StringTypeAdapter<LChar>(LChar buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return 1; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ *destination = m_buffer;
+ }
+
+ void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+ LChar m_buffer;
+};
+
+template<>
+class StringTypeAdapter<UChar> {
+public:
+ StringTypeAdapter<UChar>(UChar buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return 1; }
+
+ bool is8Bit() { return m_buffer <= 0xff; }
+
+ void writeTo(LChar* destination)
+ {
+ ASSERT(is8Bit());
+ *destination = static_cast<LChar>(m_buffer);
+ }
+
+ void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+ UChar m_buffer;
+};
+
+template<>
+class StringTypeAdapter<char*> {
+public:
+ StringTypeAdapter<char*>(char* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(buffer))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = static_cast<LChar>(m_buffer[i]);
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i) {
+ unsigned char c = m_buffer[i];
+ destination[i] = c;
+ }
+ }
+
+private:
+ const char* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<LChar*> {
+public:
+ StringTypeAdapter<LChar*>(LChar* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(reinterpret_cast<char*>(buffer)))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ memcpy(destination, m_buffer, m_length * sizeof(LChar));
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_buffer[i];
+ }
+
+private:
+ const LChar* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<const UChar*> {
+public:
+ StringTypeAdapter<const UChar*>(const UChar* buffer)
+ : m_buffer(buffer)
+ {
+ size_t len = 0;
+ while (m_buffer[len] != UChar(0))
+ len++;
+
+ if (len > std::numeric_limits<unsigned>::max())
+ CRASH();
+
+ m_length = len;
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return false; }
+
+ NO_RETURN_DUE_TO_CRASH void writeTo(LChar*)
+ {
+ CRASH();
+ }
+
+ void writeTo(UChar* destination)
+ {
+ memcpy(destination, m_buffer, m_length * sizeof(UChar));
+ }
+
+private:
+ const UChar* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<const char*> {
+public:
+ StringTypeAdapter<const char*>(const char* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(buffer))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(LChar));
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i) {
+ unsigned char c = m_buffer[i];
+ destination[i] = c;
+ }
+ }
+
+private:
+ const char* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<const LChar*> {
+public:
+ StringTypeAdapter<const LChar*>(const LChar* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(reinterpret_cast<const char*>(buffer)))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(LChar));
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_buffer[i];
+ }
+
+private:
+ const LChar* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<Vector<char> > {
+public:
+ StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ size_t length() { return m_buffer.size(); }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ for (size_t i = 0; i < m_buffer.size(); ++i)
+ destination[i] = static_cast<unsigned char>(m_buffer[i]);
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (size_t i = 0; i < m_buffer.size(); ++i)
+ destination[i] = static_cast<unsigned char>(m_buffer[i]);
+ }
+
+private:
+ const Vector<char>& m_buffer;
+};
+
+template<>
+class StringTypeAdapter<Vector<LChar> > {
+public:
+ StringTypeAdapter<Vector<LChar> >(const Vector<LChar>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ size_t length() { return m_buffer.size(); }
+
+ bool is8Bit() { return true; }
+
+ void writeTo(LChar* destination)
+ {
+ for (size_t i = 0; i < m_buffer.size(); ++i)
+ destination[i] = m_buffer[i];
+ }
+
+ void writeTo(UChar* destination)
+ {
+ for (size_t i = 0; i < m_buffer.size(); ++i)
+ destination[i] = m_buffer[i];
+ }
+
+private:
+ const Vector<LChar>& m_buffer;
+};
+
+template<>
+class StringTypeAdapter<String> {
+public:
+ StringTypeAdapter<String>(const String& string)
+ : m_buffer(string)
+ {
+ }
+
+ unsigned length() { return m_buffer.length(); }
+
+ bool is8Bit() { return m_buffer.isNull() || m_buffer.is8Bit(); }
+
+ void writeTo(LChar* destination)
+ {
+ unsigned length = m_buffer.length();
+
+ ASSERT(is8Bit());
+ const LChar* data = m_buffer.characters8();
+ for (unsigned i = 0; i < length; ++i)
+ destination[i] = data[i];
+
+ WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
+ }
+
+ void writeTo(UChar* destination)
+ {
+ unsigned length = m_buffer.length();
+
+ if (is8Bit()) {
+ const LChar* data = m_buffer.characters8();
+ for (unsigned i = 0; i < length; ++i)
+ destination[i] = data[i];
+ } else {
+ const UChar* data = m_buffer.characters16();
+ for (unsigned i = 0; i < length; ++i)
+ destination[i] = data[i];
+ }
+
+ WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
+ }
+
+private:
+ const String& m_buffer;
+};
+
+template<>
+class StringTypeAdapter<AtomicString> {
+public:
+ StringTypeAdapter<AtomicString>(const AtomicString& string)
+ : m_adapter(string.string())
+ {
+ }
+
+ unsigned length() { return m_adapter.length(); }
+
+ bool is8Bit() { return m_adapter.is8Bit(); }
+
+ void writeTo(LChar* destination) { m_adapter.writeTo(destination); }
+ void writeTo(UChar* destination) { m_adapter.writeTo(destination); }
+
+private:
+ StringTypeAdapter<String> m_adapter;
+};
+
+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);
+
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ if (overflow)
+ return 0;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+
+ return resultImpl.release();
+ }
+
+ UChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+
+ return resultImpl.release();
+}
+
+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);
+
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ if (overflow)
+ return 0;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+
+ return resultImpl.release();
+ }
+
+ UChar* buffer = 0;
+ RefPtr<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.release();
+}
+
+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);
+
+ 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;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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.release();
+}
+
+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);
+
+ 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;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit() && adapter5.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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.release();
+}
+
+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);
+
+ 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;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit() && adapter5.is8Bit() && adapter6.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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.release();
+}
+
+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);
+
+ 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;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit() && adapter5.is8Bit() && adapter6.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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.release();
+}
+
+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);
+
+ 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;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit() && adapter5.is8Bit() && adapter6.is8Bit() && adapter7.is8Bit() && adapter8.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
+{
+ 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);
+ StringTypeAdapter<StringType9> adapter9(string9);
+
+ 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);
+ sumWithOverflow(length, adapter9.length(), overflow);
+ if (overflow)
+ return 0;
+
+ if (adapter1.is8Bit() && adapter2.is8Bit() && adapter3.is8Bit() && adapter4.is8Bit() && adapter5.is8Bit() && adapter6.is8Bit() && adapter7.is8Bit() && adapter8.is8Bit() && adapter9.is8Bit()) {
+ LChar* buffer;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ LChar* 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);
+ result += adapter8.length();
+ adapter9.writeTo(result);
+
+ return resultImpl.release();
+ }
+
+ UChar* buffer;
+ RefPtr<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);
+ result += adapter8.length();
+ adapter9.writeTo(result);
+
+ return resultImpl.release();
+}
+
+
+// Convenience only.
+template<typename StringType1>
+String makeString(StringType1 string1)
+{
+ return String(string1);
+}
+
+template<typename StringType1, typename StringType2>
+String makeString(StringType1 string1, StringType2 string2)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+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)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+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)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+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)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8, string9);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+} // namespace WTF
+
+using WTF::makeString;
+
+#include "StringOperators.h"
+#endif
diff --git a/Source/JavaScriptCore/wtf/text/StringHash.h b/Source/JavaScriptCore/wtf/text/StringHash.h
new file mode 100644
index 000000000..cde591c18
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringHash.h
@@ -0,0 +1,184 @@
+/*
+ * 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;
+
+ if (a->is8Bit()) {
+ if (b->is8Bit()) {
+ // Both a & b are 8 bit.
+ return WTF::equal(a->characters8(), b->characters8(), aLength);
+ }
+
+ // We know that a is 8 bit & b is 16 bit.
+ return WTF::equal(a->characters8(), b->characters16(), aLength);
+ }
+
+ if (b->is8Bit()) {
+ // We know that a is 8 bit and b is 16 bit.
+ return WTF::equal(a->characters16(), b->characters8(), aLength);
+ }
+
+ return WTF::equal(a->characters16(), b->characters16(), aLength);
+ }
+
+ 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::computeHash<UChar, foldCase<UChar> >(data, length);
+ }
+
+ static unsigned hash(StringImpl* str)
+ {
+ return hash(str->characters(), str->length());
+ }
+
+ static unsigned hash(const LChar* data, unsigned length)
+ {
+ return StringHasher::computeHash<LChar, foldCase<LChar> >(data, length);
+ }
+
+ static inline unsigned hash(const char* data, unsigned length)
+ {
+ return CaseFoldingHash::hash(reinterpret_cast<const LChar*>(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;
+ }
+ };
+
+}
+
+using WTF::StringHash;
+using WTF::CaseFoldingHash;
+using WTF::AlreadyHashed;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/text/StringImpl.cpp b/Source/JavaScriptCore/wtf/text/StringImpl.cpp
new file mode 100644
index 000000000..aa5a8d56e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringImpl.cpp
@@ -0,0 +1,1541 @@
+/*
+ * 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;
+
+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 (has16BitShadow()) {
+ ASSERT(m_copyData16);
+ fastFree(m_copyData16);
+ }
+
+ if (ownership == BufferInternal)
+ return;
+ if (ownership == BufferOwned) {
+ // We use m_data8, but since it is a union with m_data16 this works either way.
+ ASSERT(m_data8);
+ fastFree(const_cast<LChar*>(m_data8));
+ return;
+ }
+
+ ASSERT(ownership == BufferSubstring);
+ ASSERT(m_substringBuffer);
+ m_substringBuffer->deref();
+}
+
+PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, LChar*& 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(LChar)))
+ CRASH();
+ size_t size = sizeof(StringImpl) + length * sizeof(LChar);
+ StringImpl* string = static_cast<StringImpl*>(fastMalloc(size));
+
+ data = reinterpret_cast<LChar*>(string + 1);
+ return adoptRef(new (NotNull, string) StringImpl(length, Force8BitConstructor));
+}
+
+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 (NotNull, string) StringImpl(length));
+}
+
+PassRefPtr<StringImpl> StringImpl::reallocate(PassRefPtr<StringImpl> originalString, unsigned length, LChar*& data)
+{
+ ASSERT(originalString->is8Bit());
+ ASSERT(originalString->hasOneRef());
+ ASSERT(originalString->bufferOwnership() == BufferInternal);
+
+ if (!length) {
+ data = 0;
+ return empty();
+ }
+
+ // Same as createUninitialized() except here we use fastRealloc.
+ if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(LChar)))
+ CRASH();
+ size_t size = sizeof(StringImpl) + length * sizeof(LChar);
+ originalString->~StringImpl();
+ StringImpl* string = static_cast<StringImpl*>(fastRealloc(originalString.leakRef(), size));
+
+ data = reinterpret_cast<LChar*>(string + 1);
+ return adoptRef(new (NotNull, string) StringImpl(length, Force8BitConstructor));
+}
+
+PassRefPtr<StringImpl> StringImpl::reallocate(PassRefPtr<StringImpl> originalString, unsigned length, UChar*& data)
+{
+ ASSERT(!originalString->is8Bit());
+ ASSERT(originalString->hasOneRef());
+ ASSERT(originalString->bufferOwnership() == BufferInternal);
+
+ if (!length) {
+ data = 0;
+ return empty();
+ }
+
+ // Same as createUninitialized() except here we use fastRealloc.
+ if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(UChar)))
+ CRASH();
+ size_t size = sizeof(StringImpl) + length * sizeof(UChar);
+ originalString->~StringImpl();
+ StringImpl* string = static_cast<StringImpl*>(fastRealloc(originalString.leakRef(), size));
+
+ data = reinterpret_cast<UChar*>(string + 1);
+ return adoptRef(new (NotNull, 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 LChar* characters, unsigned length)
+{
+ if (!characters || !length)
+ return empty();
+
+ LChar* data;
+ RefPtr<StringImpl> string = createUninitialized(length, data);
+ memcpy(data, characters, length * sizeof(LChar));
+ return string.release();
+}
+
+PassRefPtr<StringImpl> StringImpl::create(const LChar* string)
+{
+ if (!string)
+ return empty();
+ size_t length = strlen(reinterpret_cast<const char*>(string));
+ if (length > numeric_limits<unsigned>::max())
+ CRASH();
+ return create(string, length);
+}
+
+const UChar* StringImpl::getData16SlowCase() const
+{
+ if (has16BitShadow())
+ return m_copyData16;
+
+ if (bufferOwnership() == BufferSubstring) {
+ // If this is a substring, return a pointer into the parent string.
+ // TODO: Consider severing this string from the parent string
+ unsigned offset = m_data8 - m_substringBuffer->characters8();
+ return m_substringBuffer->characters() + offset;
+ }
+
+ unsigned len = length();
+ if (hasTerminatingNullCharacter())
+ len++;
+
+ m_copyData16 = static_cast<UChar*>(fastMalloc(len * sizeof(UChar)));
+
+ m_hashAndFlags |= s_hashFlagHas16BitShadow;
+
+ upconvertCharacters(0, len);
+
+ return m_copyData16;
+}
+
+void StringImpl::upconvertCharacters(unsigned start, unsigned end) const
+{
+ ASSERT(is8Bit());
+ ASSERT(has16BitShadow());
+
+ for (size_t i = start; i < end; i++)
+ m_copyData16[i] = m_data8[i];
+}
+
+
+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.
+ if (is8Bit()) {
+ for (unsigned i = 0; i < m_length; i++) {
+ UChar c = m_data8[i];
+ if (!isASCIISpace(c))
+ return false;
+ }
+
+ return true;
+ }
+
+ for (unsigned i = 0; i < m_length; i++) {
+ UChar c = m_data16[i];
+ if (!isASCIISpace(c))
+ 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;
+ }
+ if (is8Bit())
+ return create(m_data8 + start, length);
+
+ return create(m_data16 + start, length);
+}
+
+UChar32 StringImpl::characterStartingAt(unsigned i)
+{
+ if (is8Bit())
+ return m_data8[i];
+ if (U16_IS_SINGLE(m_data16[i]))
+ return m_data16[i];
+ if (i + 1 < m_length && U16_IS_LEAD(m_data16[i]) && U16_IS_TRAIL(m_data16[i + 1]))
+ return U16_GET_SUPPLEMENTARY(m_data16[i], m_data16[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:
+ bool noUpper = true;
+ UChar ored = 0;
+ if (is8Bit()) {
+ const LChar* end = m_data8 + m_length;
+ for (const LChar* chp = m_data8; 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;
+
+ LChar* data8;
+ RefPtr<StringImpl> newImpl = createUninitialized(length, data8);
+
+ if (!(ored & ~0x7F)) {
+ for (int32_t i = 0; i < length; i++)
+ data8[i] = toASCIILower(m_data8[i]);
+
+ return newImpl.release();
+ }
+
+ // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+ for (int32_t i = 0; i < length; i++)
+ data8[i] = static_cast<LChar>(Unicode::toLower(m_data8[i]));
+
+ return newImpl.release();
+ }
+
+ const UChar *end = m_data16 + m_length;
+ for (const UChar* chp = m_data16; 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;
+
+ if (!(ored & ~0x7F)) {
+ UChar* data16;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+
+ for (int32_t i = 0; i < length; i++) {
+ UChar c = m_data16[i];
+ data16[i] = toASCIILower(c);
+ }
+ return newImpl.release();
+ }
+
+ // Do a slower implementation for cases that include non-ASCII characters.
+ UChar* data16;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+
+ bool error;
+ int32_t realLength = Unicode::toLower(data16, length, m_data16, m_length, &error);
+ if (!error && realLength == length)
+ return newImpl.release();
+
+ newImpl = createUninitialized(realLength, data16);
+ Unicode::toLower(data16, realLength, m_data16, m_length, &error);
+ if (error)
+ return this;
+ return newImpl.release();
+}
+
+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.
+
+ if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max()))
+ CRASH();
+ int32_t length = m_length;
+
+ if (is8Bit()) {
+ LChar* data8;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data8);
+
+ // Do a faster loop for the case where all the characters are ASCII.
+ LChar ored = 0;
+ for (int i = 0; i < length; i++) {
+ LChar c = m_data8[i];
+ ored |= c;
+ data8[i] = toASCIIUpper(c);
+ }
+ if (!(ored & ~0x7F))
+ return newImpl.release();
+
+ // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+ for (int32_t i = 0; i < length; i++)
+ data8[i] = static_cast<LChar>(Unicode::toUpper(m_data8[i]));
+
+ return newImpl.release();
+ }
+
+ UChar* data16;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+
+ // 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_data16[i];
+ ored |= c;
+ data16[i] = toASCIIUpper(c);
+ }
+ if (!(ored & ~0x7F))
+ return newImpl.release();
+
+ // Do a slower implementation for cases that include non-ASCII characters.
+ bool error;
+ newImpl = createUninitialized(m_length, data16);
+ int32_t realLength = Unicode::toUpper(data16, length, m_data16, m_length, &error);
+ if (!error && realLength == length)
+ return newImpl;
+ newImpl = createUninitialized(realLength, data16);
+ Unicode::toUpper(data16, realLength, m_data16, m_length, &error);
+ if (error)
+ return this;
+ return newImpl.release();
+}
+
+PassRefPtr<StringImpl> StringImpl::fill(UChar character)
+{
+ if (!m_length)
+ return this;
+
+ if (!(character & ~0x7F)) {
+ LChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+ for (unsigned i = 0; i < m_length; ++i)
+ data[i] = character;
+ return newImpl.release();
+ }
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+ for (unsigned i = 0; i < m_length; ++i)
+ data[i] = character;
+ return newImpl.release();
+}
+
+PassRefPtr<StringImpl> StringImpl::foldCase()
+{
+ if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max()))
+ CRASH();
+ int32_t length = m_length;
+
+ if (is8Bit()) {
+ // Do a faster loop for the case where all the characters are ASCII.
+ LChar* data;
+ RefPtr <StringImpl>newImpl = createUninitialized(m_length, data);
+ LChar ored = 0;
+
+ for (int32_t i = 0; i < length; i++) {
+ LChar c = m_data8[i];
+ data[i] = toASCIILower(c);
+ ored |= c;
+ }
+
+ if (!(ored & ~0x7F))
+ return newImpl.release();
+
+ // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+ for (int32_t i = 0; i < length; i++)
+ data[i] = static_cast<LChar>(Unicode::toLower(m_data8[i]));
+
+ return newImpl.release();
+ }
+
+ // Do a faster loop for the case where all the characters are ASCII.
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+ UChar ored = 0;
+ for (int32_t i = 0; i < length; i++) {
+ UChar c = m_data16[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_data16, m_length, &error);
+ if (!error && realLength == length)
+ return newImpl.release();
+ newImpl = createUninitialized(realLength, data);
+ Unicode::foldCase(data, realLength, m_data16, m_length, &error);
+ if (error)
+ return this;
+ return newImpl.release();
+}
+
+template <class UCharPredicate>
+inline PassRefPtr<StringImpl> StringImpl::stripMatchedCharacters(UCharPredicate predicate)
+{
+ if (!m_length)
+ return empty();
+
+ unsigned start = 0;
+ unsigned end = m_length - 1;
+
+ // skip white space from start
+ while (start <= end && predicate(is8Bit() ? m_data8[start] : m_data16[start]))
+ start++;
+
+ // only white space
+ if (start > end)
+ return empty();
+
+ // skip white space from end
+ while (end && predicate(is8Bit() ? m_data8[end] : m_data16[end]))
+ end--;
+
+ if (!start && end == m_length - 1)
+ return this;
+ if (is8Bit())
+ return create(m_data8 + start, end + 1 - start);
+ return create(m_data16 + start, end + 1 - start);
+}
+
+class UCharPredicate {
+public:
+ inline UCharPredicate(CharacterMatchFunctionPtr function): m_function(function) { }
+
+ inline bool operator()(UChar ch) const
+ {
+ return m_function(ch);
+ }
+
+private:
+ const CharacterMatchFunctionPtr m_function;
+};
+
+class SpaceOrNewlinePredicate {
+public:
+ inline bool operator()(UChar ch) const
+ {
+ return isSpaceOrNewline(ch);
+ }
+};
+
+PassRefPtr<StringImpl> StringImpl::stripWhiteSpace()
+{
+ return stripMatchedCharacters(SpaceOrNewlinePredicate());
+}
+
+PassRefPtr<StringImpl> StringImpl::stripWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace)
+{
+ return stripMatchedCharacters(UCharPredicate(isWhiteSpace));
+}
+
+template <typename CharType>
+ALWAYS_INLINE PassRefPtr<StringImpl> StringImpl::removeCharacters(const CharType* characters, CharacterMatchFunctionPtr findMatch)
+{
+ const CharType* from = characters;
+ const CharType* 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<CharType> data(m_length);
+ CharType* to = data.characters();
+ unsigned outc = from - characters;
+
+ if (outc)
+ memcpy(to, characters, outc * sizeof(CharType));
+
+ 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::removeCharacters(CharacterMatchFunctionPtr findMatch)
+{
+ if (is8Bit())
+ return removeCharacters(characters8(), findMatch);
+ return removeCharacters(characters16(), findMatch);
+}
+
+template <typename CharType, class UCharPredicate>
+inline PassRefPtr<StringImpl> StringImpl::simplifyMatchedCharactersToSpace(UCharPredicate predicate)
+{
+ StringBuffer<CharType> data(m_length);
+
+ const CharType* from = getCharacters<CharType>();
+ const CharType* fromend = from + m_length;
+ int outc = 0;
+ bool changedToSpace = false;
+
+ CharType* to = data.characters();
+
+ while (true) {
+ while (from != fromend && predicate(*from)) {
+ if (*from != ' ')
+ changedToSpace = true;
+ from++;
+ }
+ while (from != fromend && !predicate(*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);
+}
+
+PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace()
+{
+ if (is8Bit())
+ return StringImpl::simplifyMatchedCharactersToSpace<LChar>(SpaceOrNewlinePredicate());
+ return StringImpl::simplifyMatchedCharactersToSpace<UChar>(SpaceOrNewlinePredicate());
+}
+
+PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace)
+{
+ if (is8Bit())
+ return StringImpl::simplifyMatchedCharactersToSpace<LChar>(UCharPredicate(isWhiteSpace));
+ return StringImpl::simplifyMatchedCharactersToSpace<UChar>(UCharPredicate(isWhiteSpace));
+}
+
+int StringImpl::toIntStrict(bool* ok, int base)
+{
+ if (is8Bit())
+ return charactersToIntStrict(characters8(), m_length, ok, base);
+ return charactersToIntStrict(characters16(), m_length, ok, base);
+}
+
+unsigned StringImpl::toUIntStrict(bool* ok, int base)
+{
+ if (is8Bit())
+ return charactersToUIntStrict(characters8(), m_length, ok, base);
+ return charactersToUIntStrict(characters16(), m_length, ok, base);
+}
+
+int64_t StringImpl::toInt64Strict(bool* ok, int base)
+{
+ if (is8Bit())
+ return charactersToInt64Strict(characters8(), m_length, ok, base);
+ return charactersToInt64Strict(characters16(), m_length, ok, base);
+}
+
+uint64_t StringImpl::toUInt64Strict(bool* ok, int base)
+{
+ if (is8Bit())
+ return charactersToUInt64Strict(characters8(), m_length, ok, base);
+ return charactersToUInt64Strict(characters16(), m_length, ok, base);
+}
+
+intptr_t StringImpl::toIntPtrStrict(bool* ok, int base)
+{
+ if (is8Bit())
+ return charactersToIntPtrStrict(characters8(), m_length, ok, base);
+ return charactersToIntPtrStrict(characters16(), m_length, ok, base);
+}
+
+int StringImpl::toInt(bool* ok)
+{
+ if (is8Bit())
+ return charactersToInt(characters8(), m_length, ok);
+ return charactersToInt(characters16(), m_length, ok);
+}
+
+unsigned StringImpl::toUInt(bool* ok)
+{
+ if (is8Bit())
+ return charactersToUInt(characters8(), m_length, ok);
+ return charactersToUInt(characters16(), m_length, ok);
+}
+
+int64_t StringImpl::toInt64(bool* ok)
+{
+ if (is8Bit())
+ return charactersToInt64(characters8(), m_length, ok);
+ return charactersToInt64(characters16(), m_length, ok);
+}
+
+uint64_t StringImpl::toUInt64(bool* ok)
+{
+ if (is8Bit())
+ return charactersToUInt64(characters8(), m_length, ok);
+ return charactersToUInt64(characters16(), m_length, ok);
+}
+
+intptr_t StringImpl::toIntPtr(bool* ok)
+{
+ if (is8Bit())
+ return charactersToIntPtr(characters8(), m_length, ok);
+ return charactersToIntPtr(characters16(), m_length, ok);
+}
+
+double StringImpl::toDouble(bool* ok, bool* didReadNumber)
+{
+ if (is8Bit())
+ return charactersToDouble(characters8(), m_length, ok, didReadNumber);
+ return charactersToDouble(characters16(), m_length, ok, didReadNumber);
+}
+
+float StringImpl::toFloat(bool* ok, bool* didReadNumber)
+{
+ if (is8Bit())
+ return charactersToFloat(characters8(), m_length, ok, didReadNumber);
+ return charactersToFloat(characters16(), m_length, ok, didReadNumber);
+}
+
+bool equalIgnoringCase(const UChar* a, const LChar* b, unsigned length)
+{
+ while (length--) {
+ LChar 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)
+{
+ if (is8Bit())
+ return WTF::find(characters8(), m_length, c, start);
+ return WTF::find(characters16(), m_length, c, start);
+}
+
+size_t StringImpl::find(CharacterMatchFunctionPtr matchFunction, unsigned start)
+{
+ if (is8Bit())
+ return WTF::find(characters8(), m_length, matchFunction, start);
+ return WTF::find(characters16(), m_length, matchFunction, start);
+}
+
+size_t StringImpl::find(const LChar* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ size_t matchStringLength = strlen(reinterpret_cast<const char*>(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(characters16(), length(), *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;
+
+ // 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 += matchString[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 LChar* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ size_t matchStringLength = strlen(reinterpret_cast<const char*>(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) {
+ if (is8Bit() && matchString->is8Bit())
+ return WTF::find(characters8(), length(), matchString->characters8()[0], index);
+ 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)
+{
+ if (is8Bit())
+ return WTF::reverseFind(characters8(), m_length, c, index);
+ return WTF::reverseFind(characters16(), 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) {
+ if (is8Bit() && matchString->is8Bit())
+ return WTF::reverseFind(characters8(), length(), matchString->characters8()[0], index);
+ 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* matchString, bool caseSensitive)
+{
+ ASSERT(matchString);
+ if (m_length >= matchString->m_length) {
+ unsigned start = m_length - matchString->m_length;
+ return (caseSensitive ? find(matchString, start) : findIgnoringCase(matchString, 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) {
+ UChar c = is8Bit() ? m_data8[i] : m_data16[i];
+ if (c == oldC)
+ break;
+ }
+ if (i == m_length)
+ return this;
+
+ if (is8Bit()) {
+ if (oldC > 0xff)
+ // Looking for a 16 bit char in an 8 bit string, we're done.
+ return this;
+
+ if (newC <= 0xff) {
+ LChar* data;
+ LChar oldChar = static_cast<LChar>(oldC);
+ LChar newChar = static_cast<LChar>(newC);
+
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+
+ for (i = 0; i != m_length; ++i) {
+ LChar ch = m_data8[i];
+ if (ch == oldChar)
+ ch = newChar;
+ data[i] = ch;
+ }
+ return newImpl.release();
+ }
+
+ // There is the possibility we need to up convert from 8 to 16 bit,
+ // create a 16 bit string for the result.
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+
+ for (i = 0; i != m_length; ++i) {
+ UChar ch = m_data8[i];
+ if (ch == oldC)
+ ch = newC;
+ data[i] = ch;
+ }
+
+ return newImpl.release();
+ }
+
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+
+ for (i = 0; i != m_length; ++i) {
+ UChar ch = m_data16[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;
+
+ if ((length() - lengthToReplace) >= (numeric_limits<unsigned>::max() - lengthToInsert))
+ CRASH();
+
+ if (is8Bit() && (!str || str->is8Bit())) {
+ LChar* data;
+ RefPtr<StringImpl> newImpl =
+ createUninitialized(length() - lengthToReplace + lengthToInsert, data);
+ memcpy(data, m_data8, position * sizeof(LChar));
+ if (str)
+ memcpy(data + position, str->m_data8, lengthToInsert * sizeof(LChar));
+ memcpy(data + position + lengthToInsert, m_data8 + position + lengthToReplace,
+ (length() - position - lengthToReplace) * sizeof(LChar));
+ return newImpl.release();
+ }
+ UChar* data;
+ RefPtr<StringImpl> newImpl =
+ createUninitialized(length() - lengthToReplace + lengthToInsert, data);
+ if (is8Bit())
+ for (unsigned i = 0; i < position; i++)
+ data[i] = m_data8[i];
+ else
+ memcpy(data, m_data16, position * sizeof(UChar));
+ if (str) {
+ if (str->is8Bit())
+ for (unsigned i = 0; i < lengthToInsert; i++)
+ data[i + position] = str->m_data8[i];
+ else
+ memcpy(data + position, str->m_data16, lengthToInsert * sizeof(UChar));
+ }
+ if (is8Bit()) {
+ for (unsigned i = 0; i < length() - position - lengthToReplace; i++)
+ data[i + position + lengthToInsert] = m_data8[i + position + lengthToReplace];
+ } else {
+ 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 then 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;
+
+ // Construct the new data.
+ size_t srcSegmentEnd;
+ unsigned srcSegmentLength;
+ srcSegmentStart = 0;
+ unsigned dstOffset = 0;
+ bool srcIs8Bit = is8Bit();
+ bool replacementIs8Bit = replacement->is8Bit();
+
+ // There are 4 cases:
+ // 1. This and replacement are both 8 bit.
+ // 2. This and replacement are both 16 bit.
+ // 3. This is 8 bit and replacement is 16 bit.
+ // 4. This is 16 bit and replacement is 8 bit.
+ if (srcIs8Bit && replacementIs8Bit) {
+ // Case 1
+ LChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+ srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+ memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+ dstOffset += srcSegmentLength;
+ memcpy(data + dstOffset, replacement->m_data8, repStrLength * sizeof(LChar));
+ dstOffset += repStrLength;
+ srcSegmentStart = srcSegmentEnd + 1;
+ }
+
+ srcSegmentLength = m_length - srcSegmentStart;
+ memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+
+ ASSERT(dstOffset + srcSegmentLength == newImpl->length());
+
+ return newImpl.release();
+ }
+
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+ srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+ if (srcIs8Bit) {
+ // Case 3.
+ for (unsigned i = 0; i < srcSegmentLength; i++)
+ data[i + dstOffset] = m_data8[i + srcSegmentStart];
+ } else {
+ // Cases 2 & 4.
+ memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+ }
+ dstOffset += srcSegmentLength;
+ if (replacementIs8Bit) {
+ // Case 4.
+ for (unsigned i = 0; i < repStrLength; i++)
+ data[i + dstOffset] = replacement->m_data8[i];
+ } else {
+ // Cases 2 & 3.
+ memcpy(data + dstOffset, replacement->m_data16, repStrLength * sizeof(UChar));
+ }
+ dstOffset += repStrLength;
+ srcSegmentStart = srcSegmentEnd + 1;
+ }
+
+ srcSegmentLength = m_length - srcSegmentStart;
+ if (srcIs8Bit) {
+ // Case 3.
+ for (unsigned i = 0; i < srcSegmentLength; i++)
+ data[i + dstOffset] = m_data8[i + srcSegmentStart];
+ } else {
+ // Cases 2 & 4.
+ memcpy(data + dstOffset, m_data16 + 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;
+
+
+ // Construct the new data
+ size_t srcSegmentEnd;
+ unsigned srcSegmentLength;
+ srcSegmentStart = 0;
+ unsigned dstOffset = 0;
+ bool srcIs8Bit = is8Bit();
+ bool replacementIs8Bit = replacement->is8Bit();
+
+ // There are 4 cases:
+ // 1. This and replacement are both 8 bit.
+ // 2. This and replacement are both 16 bit.
+ // 3. This is 8 bit and replacement is 16 bit.
+ // 4. This is 16 bit and replacement is 8 bit.
+ if (srcIs8Bit && replacementIs8Bit) {
+ // Case 1
+ LChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+ srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+ memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+ dstOffset += srcSegmentLength;
+ memcpy(data + dstOffset, replacement->m_data8, repStrLength * sizeof(LChar));
+ dstOffset += repStrLength;
+ srcSegmentStart = srcSegmentEnd + patternLength;
+ }
+
+ srcSegmentLength = m_length - srcSegmentStart;
+ memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+
+ ASSERT(dstOffset + srcSegmentLength == newImpl->length());
+
+ return newImpl.release();
+ }
+
+ UChar* data;
+ RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+ srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+ if (srcIs8Bit) {
+ // Case 3.
+ for (unsigned i = 0; i < srcSegmentLength; i++)
+ data[i + dstOffset] = m_data8[i + srcSegmentStart];
+ } else {
+ // Case 2 & 4.
+ memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+ }
+ dstOffset += srcSegmentLength;
+ if (replacementIs8Bit) {
+ // Cases 2 & 3.
+ for (unsigned i = 0; i < repStrLength; i++)
+ data[i + dstOffset] = replacement->m_data8[i];
+ } else {
+ // Case 4
+ memcpy(data + dstOffset, replacement->m_data16, repStrLength * sizeof(UChar));
+ }
+ dstOffset += repStrLength;
+ srcSegmentStart = srcSegmentEnd + patternLength;
+ }
+
+ srcSegmentLength = m_length - srcSegmentStart;
+ if (srcIs8Bit) {
+ // Case 3.
+ for (unsigned i = 0; i < srcSegmentLength; i++)
+ data[i + dstOffset] = m_data8[i + srcSegmentStart];
+ } else {
+ // Cases 2 & 4.
+ memcpy(data + dstOffset, m_data16 + 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 LChar* b, unsigned length)
+{
+ if (!a)
+ return !b;
+ if (!b)
+ return !a;
+
+ if (length != a->length())
+ return false;
+
+ if (a->is8Bit())
+ return equal(a->characters8(), b, length);
+ return equal(a->characters16(), b, length);
+}
+
+bool equal(const StringImpl* a, const LChar* b)
+{
+ if (!a)
+ return !b;
+ if (!b)
+ return !a;
+
+ unsigned length = a->length();
+
+ if (a->is8Bit()) {
+ const LChar* aPtr = a->characters8();
+ for (unsigned i = 0; i != length; ++i) {
+ LChar bc = b[i];
+ LChar ac = aPtr[i];
+ if (!bc)
+ return false;
+ if (ac != bc)
+ return false;
+ }
+
+ return !b[length];
+ }
+
+ const UChar* aPtr = a->characters16();
+ for (unsigned i = 0; i != length; ++i) {
+ LChar bc = b[i];
+ if (!bc)
+ return false;
+ if (aPtr[i] != bc)
+ return false;
+ }
+
+ return !b[length];
+}
+
+bool equal(const StringImpl* a, const UChar* b, unsigned length)
+{
+ if (!a)
+ return !b;
+ if (!b)
+ return false;
+
+ if (a->length() != length)
+ return false;
+ if (a->is8Bit())
+ return equal(a->characters8(), b, length);
+ return equal(a->characters16(), b, length);
+}
+
+bool equalIgnoringCase(StringImpl* a, StringImpl* b)
+{
+ return CaseFoldingHash::equal(a, b);
+}
+
+bool equalIgnoringCase(StringImpl* a, const LChar* b)
+{
+ if (!a)
+ return !b;
+ if (!b)
+ return !a;
+
+ unsigned length = a->length();
+
+ // Do a faster loop for the case where all the characters are ASCII.
+ UChar ored = 0;
+ bool equal = true;
+ if (a->is8Bit()) {
+ const LChar* as = a->characters8();
+ for (unsigned i = 0; i != length; ++i) {
+ LChar 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)
+ equal = equal && (foldCase(as[i]) == foldCase(b[i]));
+ }
+
+ return equal && !b[length];
+ }
+
+ const UChar* as = a->characters16();
+ for (unsigned i = 0; i != length; ++i) {
+ LChar 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) {
+ equal = equal && (foldCase(as[i]) == foldCase(b[i]));
+ }
+ }
+
+ 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(bool* hasStrongDirectionality)
+{
+ for (unsigned i = 0; i < m_length; ++i) {
+ WTF::Unicode::Direction charDirection = WTF::Unicode::direction(is8Bit() ? m_data8[i] : m_data16[i]);
+ if (charDirection == WTF::Unicode::LeftToRight) {
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = true;
+ return WTF::Unicode::LeftToRight;
+ }
+ if (charDirection == WTF::Unicode::RightToLeft || charDirection == WTF::Unicode::RightToLeftArabic) {
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = true;
+ return WTF::Unicode::RightToLeft;
+ }
+ }
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = false;
+ return WTF::Unicode::LeftToRight;
+}
+
+PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer<LChar>& buffer)
+{
+unsigned length = buffer.length();
+if (!length)
+ return empty();
+return adoptRef(new StringImpl(buffer.release(), length));
+}
+
+PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer<UChar>& buffer)
+{
+ unsigned length = buffer.length();
+ if (!length)
+ 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.
+ unsigned length = string.m_length;
+ if (length >= numeric_limits<unsigned>::max())
+ CRASH();
+ RefPtr<StringImpl> terminatedString;
+ if (string.is8Bit()) {
+ LChar* data;
+ terminatedString = createUninitialized(length + 1, data);
+ memcpy(data, string.m_data8, length * sizeof(LChar));
+ data[length] = 0;
+ } else {
+ UChar* data;
+ terminatedString = createUninitialized(length + 1, data);
+ memcpy(data, string.m_data16, length * sizeof(UChar));
+ data[length] = 0;
+ }
+ terminatedString->m_length--;
+ terminatedString->m_hashAndFlags = (string.m_hashAndFlags & (~s_flagMask | s_hashFlag8BitBuffer)) | s_hashFlagHasTerminatingNullCharacter;
+ return terminatedString.release();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/text/StringImpl.h b/Source/JavaScriptCore/wtf/text/StringImpl.h
new file mode 100644
index 000000000..a3008e1d3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringImpl.h
@@ -0,0 +1,774 @@
+/*
+ * 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/Forward.h>
+#include <wtf/OwnFastMallocPtr.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringHasher.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+#if USE(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;
+template <typename T> struct IdentifierCharBufferTranslator;
+struct IdentifierLCharFromUCharTranslator;
+}
+
+namespace WTF {
+
+struct CStringTranslator;
+struct HashAndCharactersTranslator;
+struct HashAndUTF8CharactersTranslator;
+struct UCharBufferTranslator;
+
+enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
+
+typedef bool (*CharacterMatchFunctionPtr)(UChar);
+typedef bool (*IsWhiteSpaceFunctionPtr)(UChar);
+
+class StringImpl {
+ WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_FAST_ALLOCATED;
+ friend struct JSC::IdentifierCStringTranslator;
+ friend struct JSC::IdentifierCharBufferTranslator<LChar>;
+ friend struct JSC::IdentifierCharBufferTranslator<UChar>;
+ friend struct JSC::IdentifierLCharFromUCharTranslator;
+ friend struct WTF::CStringTranslator;
+ friend struct WTF::HashAndCharactersTranslator;
+ friend struct WTF::HashAndUTF8CharactersTranslator;
+ friend struct WTF::UCharBufferTranslator;
+ friend class AtomicStringImpl;
+
+private:
+ enum BufferOwnership {
+ BufferInternal,
+ BufferOwned,
+ BufferSubstring,
+ };
+
+ // 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.
+ enum ConstructStaticStringTag { ConstructStaticString };
+ StringImpl(const UChar* characters, unsigned length, ConstructStaticStringTag)
+ : m_refCount(s_refCountFlagIsStaticString)
+ , m_length(length)
+ , m_data16(characters)
+ , m_buffer(0)
+ , m_hashAndFlags(s_hashFlagIsIdentifier | BufferOwned)
+ {
+ // 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();
+ }
+
+ // 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 LChar* characters, unsigned length, ConstructStaticStringTag)
+ : m_refCount(s_refCountFlagIsStaticString)
+ , m_length(length)
+ , m_data8(characters)
+ , m_buffer(0)
+ , m_hashAndFlags(s_hashFlag8BitBuffer | s_hashFlagIsIdentifier | BufferOwned)
+ {
+ // 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();
+ }
+
+ // FIXME: there has to be a less hacky way to do this.
+ enum Force8Bit { Force8BitConstructor };
+ // Create a normal 8-bit string with internal storage (BufferInternal)
+ StringImpl(unsigned length, Force8Bit)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data8(reinterpret_cast<const LChar*>(this + 1))
+ , m_buffer(0)
+ , m_hashAndFlags(s_hashFlag8BitBuffer | BufferInternal)
+ {
+ ASSERT(m_data8);
+ ASSERT(m_length);
+ }
+
+ // Create a normal 16-bit string with internal storage (BufferInternal)
+ StringImpl(unsigned length)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data16(reinterpret_cast<const UChar*>(this + 1))
+ , m_buffer(0)
+ , m_hashAndFlags(BufferInternal)
+ {
+ ASSERT(m_data16);
+ ASSERT(m_length);
+ }
+
+ // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
+ StringImpl(const LChar* characters, unsigned length)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data8(characters)
+ , m_buffer(0)
+ , m_hashAndFlags(s_hashFlag8BitBuffer | BufferOwned)
+ {
+ ASSERT(m_data8);
+ ASSERT(m_length);
+ }
+
+ // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
+ StringImpl(const UChar* characters, unsigned length)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data16(characters)
+ , m_buffer(0)
+ , m_hashAndFlags(BufferOwned)
+ {
+ ASSERT(m_data16);
+ ASSERT(m_length);
+ }
+
+ // Used to create new strings that are a substring of an existing 8-bit StringImpl (BufferSubstring)
+ StringImpl(const LChar* characters, unsigned length, PassRefPtr<StringImpl> base)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data8(characters)
+ , m_substringBuffer(base.leakRef())
+ , m_hashAndFlags(s_hashFlag8BitBuffer | BufferSubstring)
+ {
+ ASSERT(is8Bit());
+ ASSERT(m_data8);
+ ASSERT(m_length);
+ ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
+ }
+
+ // Used to create new strings that are a substring of an existing 16-bit StringImpl (BufferSubstring)
+ StringImpl(const UChar* characters, unsigned length, PassRefPtr<StringImpl> base)
+ : m_refCount(s_refCountIncrement)
+ , m_length(length)
+ , m_data16(characters)
+ , m_substringBuffer(base.leakRef())
+ , m_hashAndFlags(BufferSubstring)
+ {
+ ASSERT(!is8Bit());
+ ASSERT(m_data16);
+ ASSERT(m_length);
+ ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
+ }
+
+public:
+ ~StringImpl();
+
+ static PassRefPtr<StringImpl> create(const UChar*, unsigned length);
+ static PassRefPtr<StringImpl> create(const LChar*, unsigned length);
+ ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s, unsigned length) { return create(reinterpret_cast<const LChar*>(s), length); }
+ static PassRefPtr<StringImpl> create(const LChar*);
+ ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s) { return create(reinterpret_cast<const LChar*>(s)); }
+
+ static ALWAYS_INLINE PassRefPtr<StringImpl> create8(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length)
+ {
+ ASSERT(rep);
+ ASSERT(length <= rep->length());
+
+ if (!length)
+ return empty();
+
+ ASSERT(rep->is8Bit());
+ StringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get();
+ return adoptRef(new StringImpl(rep->m_data8 + offset, length, ownerRep));
+ }
+
+ 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();
+ if (rep->is8Bit())
+ return adoptRef(new StringImpl(rep->m_data8 + offset, length, ownerRep));
+ return adoptRef(new StringImpl(rep->m_data16 + offset, length, ownerRep));
+ }
+
+ static PassRefPtr<StringImpl> createUninitialized(unsigned length, LChar*& data);
+ static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data);
+ template <typename T> static ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, T*& output)
+ {
+ if (!length) {
+ output = 0;
+ return empty();
+ }
+
+ if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(T))) {
+ output = 0;
+ return 0;
+ }
+ StringImpl* resultImpl;
+ if (!tryFastMalloc(sizeof(T) * length + sizeof(StringImpl)).getValue(resultImpl)) {
+ output = 0;
+ return 0;
+ }
+ output = reinterpret_cast<T*>(resultImpl + 1);
+
+ if (sizeof(T) == sizeof(char))
+ return adoptRef(new (NotNull, resultImpl) StringImpl(length, Force8BitConstructor));
+
+ return adoptRef(new (NotNull, resultImpl) StringImpl(length));
+ }
+
+ // Reallocate the StringImpl. The originalString must be only owned by the PassRefPtr,
+ // and the buffer ownership must be BufferInternal. Just like the input pointer of realloc(),
+ // the originalString can't be used after this function.
+ static PassRefPtr<StringImpl> reallocate(PassRefPtr<StringImpl> originalString, unsigned length, LChar*& data);
+ static PassRefPtr<StringImpl> reallocate(PassRefPtr<StringImpl> originalString, unsigned length, UChar*& data);
+
+ static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); }
+ static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
+ static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
+ static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&);
+
+ template<typename CharType, size_t inlineCapacity>
+ static PassRefPtr<StringImpl> adopt(Vector<CharType, 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<LChar>& buffer);
+ static PassRefPtr<StringImpl> adopt(StringBuffer<UChar>& buffer);
+
+ unsigned length() const { return m_length; }
+ bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; }
+
+ // FIXME: Remove all unnecessary usages of characters()
+ ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); return m_data8; }
+ ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return m_data16; }
+ ALWAYS_INLINE const UChar* characters() const
+ {
+ if (!is8Bit())
+ return m_data16;
+
+ return getData16SlowCase();
+ }
+
+ template <typename CharType>
+ ALWAYS_INLINE const CharType * getCharacters() const;
+
+ size_t cost()
+ {
+ // For substrings, return the cost of the base string.
+ if (bufferOwnership() == BufferSubstring)
+ return m_substringBuffer->cost();
+
+ if (m_hashAndFlags & s_hashFlagDidReportCost)
+ return 0;
+
+ m_hashAndFlags |= s_hashFlagDidReportCost;
+ return m_length;
+ }
+
+ bool has16BitShadow() const { return m_hashAndFlags & s_hashFlagHas16BitShadow; }
+ void upconvertCharacters(unsigned, unsigned) const;
+ bool isIdentifier() const { return m_hashAndFlags & s_hashFlagIsIdentifier; }
+ void setIsIdentifier(bool isIdentifier)
+ {
+ ASSERT(!isStatic());
+ if (isIdentifier)
+ m_hashAndFlags |= s_hashFlagIsIdentifier;
+ else
+ m_hashAndFlags &= ~s_hashFlagIsIdentifier;
+ }
+
+ bool hasTerminatingNullCharacter() const { return m_hashAndFlags & s_hashFlagHasTerminatingNullCharacter; }
+
+ bool isAtomic() const { return m_hashAndFlags & s_hashFlagIsAtomic; }
+ void setIsAtomic(bool isIdentifier)
+ {
+ ASSERT(!isStatic());
+ if (isIdentifier)
+ m_hashAndFlags |= s_hashFlagIsAtomic;
+ else
+ m_hashAndFlags &= ~s_hashFlagIsAtomic;
+ }
+
+private:
+ // The high bits of 'hash' are always empty, but we prefer to store our flags
+ // in the low bits because it makes them slightly more efficient to access.
+ // So, we shift left and right when setting and getting our hash code.
+ void setHash(unsigned hash) const
+ {
+ ASSERT(!hasHash());
+ // Multiple clients assume that StringHasher is the canonical string hash function.
+ ASSERT(hash == (is8Bit() ? StringHasher::computeHash(m_data8, m_length) : StringHasher::computeHash(m_data16, m_length)));
+ ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // Verify that enough high bits are empty.
+
+ hash <<= s_flagCount;
+ ASSERT(!(hash & m_hashAndFlags)); // Verify that enough low bits are empty after shift.
+ ASSERT(hash); // Verify that 0 is a valid sentinel hash value.
+
+ m_hashAndFlags |= hash; // Store hash with flags in low bits.
+ }
+
+ unsigned rawHash() const
+ {
+ return m_hashAndFlags >> s_flagCount;
+ }
+
+public:
+ bool hasHash() const
+ {
+ return rawHash() != 0;
+ }
+
+ unsigned existingHash() const
+ {
+ ASSERT(hasHash());
+ return rawHash();
+ }
+
+ unsigned hash() const
+ {
+ if (hasHash())
+ return existingHash();
+ return hashSlowCase();
+ }
+
+ inline bool hasOneRef() const
+ {
+ return m_refCount == s_refCountIncrement;
+ }
+
+ inline void ref()
+ {
+ m_refCount += s_refCountIncrement;
+ }
+
+ inline void deref()
+ {
+ if (m_refCount == s_refCountIncrement) {
+ delete this;
+ return;
+ }
+
+ m_refCount -= s_refCountIncrement;
+ }
+
+ static StringImpl* empty();
+
+ // FIXME: Does this really belong in StringImpl?
+ template <typename T> static void copyChars(T* destination, const T* source, unsigned numCharacters)
+ {
+ if (numCharacters == 1) {
+ *destination = *source;
+ return;
+ }
+
+ if (numCharacters <= s_copyCharsInlineCutOff) {
+ unsigned i = 0;
+#if (CPU(X86) || CPU(X86_64))
+ const unsigned charsPerInt = sizeof(uint32_t) / sizeof(T);
+
+ if (numCharacters > charsPerInt) {
+ unsigned stopCount = numCharacters & ~(charsPerInt - 1);
+
+ const uint32_t* srcCharacters = reinterpret_cast<const uint32_t*>(source);
+ uint32_t* destCharacters = reinterpret_cast<uint32_t*>(destination);
+ for (unsigned j = 0; i < stopCount; i += charsPerInt, ++j)
+ destCharacters[j] = srcCharacters[j];
+ }
+#endif
+ for (; i < numCharacters; ++i)
+ destination[i] = source[i];
+ } else
+ memcpy(destination, source, numCharacters * sizeof(T));
+ }
+
+ // Some string features, like refcounting and the atomicity flag, are not
+ // thread-safe. We achieve thread safety by isolation, giving each thread
+ // its own copy of the string.
+ PassRefPtr<StringImpl> isolatedCopy() const;
+
+ PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX);
+
+ UChar operator[](unsigned i) const
+ {
+ ASSERT(i < m_length);
+ if (is8Bit())
+ return m_data8[i];
+ return m_data16[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, bool* didReadNumber = 0);
+ float toFloat(bool* ok = 0, bool* didReadNumber = 0);
+
+ PassRefPtr<StringImpl> lower();
+ PassRefPtr<StringImpl> upper();
+
+ PassRefPtr<StringImpl> fill(UChar);
+ // FIXME: Do we need fill(char) or can we just do the right thing if UChar is ASCII?
+ PassRefPtr<StringImpl> foldCase();
+
+ PassRefPtr<StringImpl> stripWhiteSpace();
+ PassRefPtr<StringImpl> stripWhiteSpace(IsWhiteSpaceFunctionPtr);
+ PassRefPtr<StringImpl> simplifyWhiteSpace();
+ PassRefPtr<StringImpl> simplifyWhiteSpace(IsWhiteSpaceFunctionPtr);
+
+ PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr);
+ template <typename CharType>
+ ALWAYS_INLINE PassRefPtr<StringImpl> removeCharacters(const CharType* characters, CharacterMatchFunctionPtr);
+
+ size_t find(UChar, unsigned index = 0);
+ size_t find(CharacterMatchFunctionPtr, unsigned index = 0);
+ size_t find(const LChar*, unsigned index = 0);
+ ALWAYS_INLINE size_t find(const char* s, unsigned index = 0) { return find(reinterpret_cast<const LChar*>(s), index); };
+ size_t find(StringImpl*, unsigned index = 0);
+ size_t findIgnoringCase(const LChar*, unsigned index = 0);
+ ALWAYS_INLINE size_t findIgnoringCase(const char* s, unsigned index = 0) { return findIgnoringCase(reinterpret_cast<const LChar*>(s), index); };
+ 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(bool* hasStrongDirectionality = 0);
+
+#if USE(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;
+
+ BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_hashAndFlags & s_hashMaskBufferOwnership); }
+ bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; }
+ template <class UCharPredicate> PassRefPtr<StringImpl> stripMatchedCharacters(UCharPredicate);
+ template <typename CharType, class UCharPredicate> PassRefPtr<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
+ NEVER_INLINE const UChar* getData16SlowCase() const;
+ NEVER_INLINE unsigned hashSlowCase() const;
+
+ // The bottom bit in the ref count indicates a static (immortal) string.
+ static const unsigned s_refCountFlagIsStaticString = 0x1;
+ static const unsigned s_refCountIncrement = 0x2; // This allows us to ref / deref without disturbing the static string flag.
+
+ // The bottom 8 bits in the hash are flags.
+ static const unsigned s_flagCount = 8;
+ static const unsigned s_flagMask = (1u << s_flagCount) - 1;
+ COMPILE_ASSERT(s_flagCount == StringHasher::flagCount, StringHasher_reserves_enough_bits_for_StringImpl_flags);
+
+ static const unsigned s_hashFlagHas16BitShadow = 1u << 7;
+ static const unsigned s_hashFlag8BitBuffer = 1u << 6;
+ static const unsigned s_hashFlagHasTerminatingNullCharacter = 1u << 5;
+ static const unsigned s_hashFlagIsAtomic = 1u << 4;
+ static const unsigned s_hashFlagDidReportCost = 1u << 3;
+ static const unsigned s_hashFlagIsIdentifier = 1u << 2;
+ static const unsigned s_hashMaskBufferOwnership = 1u | (1u << 1);
+
+ unsigned m_refCount;
+ unsigned m_length;
+ union {
+ const LChar* m_data8;
+ const UChar* m_data16;
+ };
+ union {
+ void* m_buffer;
+ StringImpl* m_substringBuffer;
+ mutable UChar* m_copyData16;
+ };
+ mutable unsigned m_hashAndFlags;
+};
+
+template <>
+ALWAYS_INLINE const LChar* StringImpl::getCharacters<LChar>() const { return characters8(); }
+
+template <>
+ALWAYS_INLINE const UChar* StringImpl::getCharacters<UChar>() const { return characters16(); }
+
+bool equal(const StringImpl*, const StringImpl*);
+bool equal(const StringImpl*, const LChar*);
+inline bool equal(const StringImpl* a, const char* b) { return equal(a, reinterpret_cast<const LChar*>(b)); }
+bool equal(const StringImpl*, const LChar*, unsigned);
+inline bool equal(const StringImpl* a, const char* b, unsigned length) { return equal(a, reinterpret_cast<const LChar*>(b), length); }
+inline bool equal(const LChar* a, StringImpl* b) { return equal(b, a); }
+inline bool equal(const char* a, StringImpl* b) { return equal(b, reinterpret_cast<const LChar*>(a)); }
+bool equal(const StringImpl*, const UChar*, unsigned);
+
+// Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe.
+#if CPU(X86_64)
+ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
+{
+ unsigned dwordLength = length >> 3;
+
+ if (dwordLength) {
+ const uint64_t* aDWordCharacters = reinterpret_cast<const uint64_t*>(a);
+ const uint64_t* bDWordCharacters = reinterpret_cast<const uint64_t*>(b);
+
+ for (unsigned i = 0; i != dwordLength; ++i) {
+ if (*aDWordCharacters++ != *bDWordCharacters++)
+ return false;
+ }
+
+ a = reinterpret_cast<const LChar*>(aDWordCharacters);
+ b = reinterpret_cast<const LChar*>(bDWordCharacters);
+ }
+
+ if (length & 4) {
+ if (*reinterpret_cast<const uint32_t*>(a) != *reinterpret_cast<const uint32_t*>(b))
+ return false;
+
+ a += 4;
+ b += 4;
+ }
+
+ if (length & 2) {
+ if (*reinterpret_cast<const uint16_t*>(a) != *reinterpret_cast<const uint16_t*>(b))
+ return false;
+
+ a += 2;
+ b += 2;
+ }
+
+ if (length & 1 && (*a != *b))
+ return false;
+
+ return true;
+}
+
+ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
+{
+ unsigned dwordLength = length >> 2;
+
+ if (dwordLength) {
+ const uint64_t* aDWordCharacters = reinterpret_cast<const uint64_t*>(a);
+ const uint64_t* bDWordCharacters = reinterpret_cast<const uint64_t*>(b);
+
+ for (unsigned i = 0; i != dwordLength; ++i) {
+ if (*aDWordCharacters++ != *bDWordCharacters++)
+ return false;
+ }
+
+ a = reinterpret_cast<const UChar*>(aDWordCharacters);
+ b = reinterpret_cast<const UChar*>(bDWordCharacters);
+ }
+
+ if (length & 2) {
+ if (*reinterpret_cast<const uint32_t*>(a) != *reinterpret_cast<const uint32_t*>(b))
+ return false;
+
+ a += 2;
+ b += 2;
+ }
+
+ if (length & 1 && (*a != *b))
+ return false;
+
+ return true;
+}
+#elif CPU(X86)
+ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
+{
+ const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a);
+ const uint32_t* bCharacters = reinterpret_cast<const uint32_t*>(b);
+
+ unsigned wordLength = length >> 2;
+ for (unsigned i = 0; i != wordLength; ++i) {
+ if (*aCharacters++ != *bCharacters++)
+ return false;
+ }
+
+ length &= 3;
+
+ if (length) {
+ const LChar* aRemainder = reinterpret_cast<const LChar*>(aCharacters);
+ const LChar* bRemainder = reinterpret_cast<const LChar*>(bCharacters);
+
+ for (unsigned i = 0; i < length; ++i) {
+ if (aRemainder[i] != bRemainder[i])
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
+{
+ const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a);
+ const uint32_t* bCharacters = reinterpret_cast<const uint32_t*>(b);
+
+ unsigned wordLength = length >> 1;
+ for (unsigned i = 0; i != wordLength; ++i) {
+ if (*aCharacters++ != *bCharacters++)
+ return false;
+ }
+
+ if (length & 1 && *reinterpret_cast<const UChar*>(aCharacters) != *reinterpret_cast<const UChar*>(bCharacters))
+ return false;
+
+ return true;
+}
+#else
+ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
+{
+ for (unsigned i = 0; i != length; ++i) {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+}
+
+ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
+{
+ for (unsigned i = 0; i != length; ++i) {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+ALWAYS_INLINE bool equal(const LChar* a, const UChar* b, unsigned length)
+{
+ for (unsigned i = 0; i != length; ++i) {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+}
+
+ALWAYS_INLINE bool equal(const UChar* a, const LChar* b, unsigned length)
+{
+ for (unsigned i = 0; i != length; ++i) {
+ if (a[i] != b[i])
+ return false;
+ }
+
+ return true;
+}
+
+bool equalIgnoringCase(StringImpl*, StringImpl*);
+bool equalIgnoringCase(StringImpl*, const LChar*);
+inline bool equalIgnoringCase(const LChar* a, StringImpl* b) { return equalIgnoringCase(b, a); }
+bool equalIgnoringCase(const UChar*, const LChar*, unsigned);
+inline bool equalIgnoringCase(const UChar* a, const char* b, unsigned length) { return equalIgnoringCase(a, reinterpret_cast<const LChar*>(b), length); }
+inline bool equalIgnoringCase(const LChar* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, a, length); }
+inline bool equalIgnoringCase(const char* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, reinterpret_cast<const LChar*>(a), length); }
+
+bool equalIgnoringNullity(StringImpl*, StringImpl*);
+
+template<size_t inlineCapacity>
+bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b)
+{
+ if (!b)
+ return !a.size();
+ if (a.size() != b->length())
+ return false;
+ return !memcmp(a.data(), b->characters(), b->length());
+}
+
+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;
+}
+
+inline PassRefPtr<StringImpl> StringImpl::isolatedCopy() const
+{
+ if (is8Bit())
+ return create(m_data8, m_length);
+ return create(m_data16, m_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/Source/JavaScriptCore/wtf/text/StringOperators.h b/Source/JavaScriptCore/wtf/text/StringOperators.h
new file mode 100644
index 000000000..9e1637be1
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringOperators.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2011. 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 StringOperators_h
+#define StringOperators_h
+
+namespace WTF {
+
+template<typename StringType1, typename StringType2>
+class StringAppend {
+public:
+ StringAppend(StringType1 string1, StringType2 string2)
+ : m_string1(string1)
+ , m_string2(string2)
+ {
+ }
+
+ operator String() const
+ {
+ RefPtr<StringImpl> resultImpl = tryMakeString(m_string1, m_string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+ }
+
+ operator AtomicString() const
+ {
+ return operator String();
+ }
+
+ bool is8Bit()
+ {
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ return adapter1.is8Bit() && adapter2.is8Bit();
+ }
+
+ void writeTo(LChar* destination)
+ {
+ ASSERT(is8Bit());
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ adapter1.writeTo(destination);
+ adapter2.writeTo(destination + adapter1.length());
+ }
+
+ void writeTo(UChar* destination)
+ {
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ adapter1.writeTo(destination);
+ adapter2.writeTo(destination + adapter1.length());
+ }
+
+ unsigned length()
+ {
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ return adapter1.length() + adapter2.length();
+ }
+
+private:
+ StringType1 m_string1;
+ StringType2 m_string2;
+};
+
+template<typename StringType1, typename StringType2>
+class StringTypeAdapter<StringAppend<StringType1, StringType2> > {
+public:
+ StringTypeAdapter<StringAppend<StringType1, StringType2> >(StringAppend<StringType1, StringType2>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return m_buffer.length(); }
+
+ bool is8Bit() { return m_buffer.is8Bit(); }
+
+ void writeTo(LChar* destination) { m_buffer.writeTo(destination); }
+ void writeTo(UChar* destination) { m_buffer.writeTo(destination); }
+
+private:
+ StringAppend<StringType1, StringType2>& m_buffer;
+};
+
+inline StringAppend<const char*, String> operator+(const char* string1, const String& string2)
+{
+ return StringAppend<const char*, String>(string1, string2);
+}
+
+inline StringAppend<const char*, AtomicString> operator+(const char* string1, const AtomicString& string2)
+{
+ return StringAppend<const char*, AtomicString>(string1, string2);
+}
+
+template<typename U, typename V>
+StringAppend<const char*, StringAppend<U, V> > operator+(const char* string1, const StringAppend<U, V>& string2)
+{
+ return StringAppend<const char*, StringAppend<U, V> >(string1, string2);
+}
+
+inline StringAppend<const UChar*, String> operator+(const UChar* string1, const String& string2)
+{
+ return StringAppend<const UChar*, String>(string1, string2);
+}
+
+inline StringAppend<const UChar*, AtomicString> operator+(const UChar* string1, const AtomicString& string2)
+{
+ return StringAppend<const UChar*, AtomicString>(string1, string2);
+}
+
+template<typename U, typename V>
+StringAppend<const UChar*, StringAppend<U, V> > operator+(const UChar* string1, const StringAppend<U, V>& string2)
+{
+ return StringAppend<const UChar*, StringAppend<U, V> >(string1, string2);
+}
+
+template<typename T>
+StringAppend<String, T> operator+(const String& string1, T string2)
+{
+ return StringAppend<String, T>(string1, string2);
+}
+
+template<typename U, typename V, typename W>
+StringAppend<StringAppend<U, V>, W> operator+(const StringAppend<U, V>& string1, W string2)
+{
+ return StringAppend<StringAppend<U, V>, W>(string1, string2);
+}
+
+} // namespace WTF
+
+#endif // StringOperators_h
diff --git a/Source/JavaScriptCore/wtf/text/StringStatics.cpp b/Source/JavaScriptCore/wtf/text/StringStatics.cpp
new file mode 100644
index 000000000..1a80f6d48
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/StringStatics.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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 "DynamicAnnotations.h"
+#include "MainThread.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 LChar emptyLCharData = 0;
+ DEFINE_STATIC_LOCAL(StringImpl, emptyString, (&emptyLCharData, 0, ConstructStaticString));
+ WTF_ANNOTATE_BENIGN_RACE(&emptyString, "Benign race on StringImpl::emptyString reference counter");
+ return &emptyString;
+}
+
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, nullAtom)
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, emptyAtom, "")
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, textAtom, "#text")
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, commentAtom, "#comment")
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, starAtom, "*")
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, xmlAtom, "xml")
+WTF_EXPORTDATA DEFINE_GLOBAL(AtomicString, xmlnsAtom, "xmlns")
+
+NEVER_INLINE unsigned StringImpl::hashSlowCase() const
+{
+ if (is8Bit())
+ setHash(StringHasher::computeHash(m_data8, m_length));
+ else
+ setHash(StringHasher::computeHash(m_data16, m_length));
+ return existingHash();
+}
+
+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 (NotNull, (void*)&nullAtom) AtomicString;
+ new (NotNull, (void*)&emptyAtom) AtomicString("");
+ new (NotNull, (void*)&textAtom) AtomicString("#text");
+ new (NotNull, (void*)&commentAtom) AtomicString("#comment");
+ new (NotNull, (void*)&starAtom) AtomicString("*");
+ new (NotNull, (void*)&xmlAtom) AtomicString("xml");
+ new (NotNull, (void*)&xmlnsAtom) AtomicString("xmlns");
+
+ initialized = true;
+ }
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/text/TextPosition.h b/Source/JavaScriptCore/wtf/text/TextPosition.h
new file mode 100644
index 000000000..be49c157a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/TextPosition.h
@@ -0,0 +1,85 @@
+/*
+ * 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 {
+
+// An abstract number of element in a sequence. The sequence has a first element.
+// This type should be used instead of integer because 2 contradicting traditions can
+// call a first element '0' or '1' which makes integer type ambiguous.
+class OrdinalNumber {
+public:
+ static OrdinalNumber fromZeroBasedInt(int zeroBasedInt) { return OrdinalNumber(zeroBasedInt); }
+ static OrdinalNumber fromOneBasedInt(int oneBasedInt) { return OrdinalNumber(oneBasedInt - 1); }
+ OrdinalNumber() : m_zeroBasedValue(0) { }
+
+ int zeroBasedInt() const { return m_zeroBasedValue; }
+ int oneBasedInt() const { return m_zeroBasedValue + 1; }
+
+ bool operator==(OrdinalNumber other) { return m_zeroBasedValue == other.m_zeroBasedValue; }
+ bool operator!=(OrdinalNumber other) { return !((*this) == other); }
+
+ static OrdinalNumber first() { return OrdinalNumber(0); }
+ static OrdinalNumber beforeFirst() { return OrdinalNumber(-1); }
+
+private:
+ OrdinalNumber(int zeroBasedInt) : m_zeroBasedValue(zeroBasedInt) { }
+ int m_zeroBasedValue;
+};
+
+
+// TextPosition structure specifies coordinates within an text resource. It is used mostly
+// for saving script source position.
+class TextPosition {
+public:
+ TextPosition(OrdinalNumber line, OrdinalNumber column)
+ : m_line(line)
+ , m_column(column)
+ {
+ }
+ TextPosition() { }
+ bool operator==(const TextPosition& other) { return m_line == other.m_line && m_column == other.m_column; }
+ bool operator!=(const TextPosition& other) { return !((*this) == other); }
+
+ // A 'minimum' value of position, used as a default value.
+ static TextPosition minimumPosition() { return TextPosition(OrdinalNumber::first(), OrdinalNumber::first()); }
+
+ // A value with line value less than a minimum; used as an impossible position.
+ static TextPosition belowRangePosition() { return TextPosition(OrdinalNumber::beforeFirst(), OrdinalNumber::beforeFirst()); }
+
+ OrdinalNumber m_line;
+ OrdinalNumber m_column;
+};
+
+}
+
+using WTF::OrdinalNumber;
+
+using WTF::TextPosition;
+
+#endif // TextPosition_h
diff --git a/Source/JavaScriptCore/wtf/text/WTFString.cpp b/Source/JavaScriptCore/wtf/text/WTFString.cpp
new file mode 100644
index 000000000..4c42ed6a2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/WTFString.cpp
@@ -0,0 +1,1126 @@
+/*
+ * (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 LChar* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
+{
+}
+
+String::String(const char* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters), length) : 0)
+{
+}
+
+// Construct a string with latin1 data, from a null-terminated source.
+String::String(const LChar* characters)
+ : m_impl(characters ? StringImpl::create(characters) : 0)
+{
+}
+
+String::String(const char* characters)
+ : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(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(LChar 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);
+}
+
+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::stripWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace) const
+{
+ if (!m_impl)
+ return String();
+ return m_impl->stripWhiteSpace(isWhiteSpace);
+}
+
+String String::simplifyWhiteSpace() const
+{
+ if (!m_impl)
+ return String();
+ return m_impl->simplifyWhiteSpace();
+}
+
+String String::simplifyWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace) const
+{
+ if (!m_impl)
+ return String();
+ return m_impl->simplifyWhiteSpace(isWhiteSpace);
+}
+
+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(reinterpret_cast<const LChar*>(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(reinterpret_cast<const LChar*>(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(reinterpret_cast<const LChar*>(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 number, unsigned flags, unsigned precision)
+{
+ NumberToStringBuffer buffer;
+
+ // Mimic String::format("%.[precision]g", ...), but use dtoas rounding facilities.
+ if (flags & ShouldRoundSignificantFigures)
+ return String(numberToFixedPrecisionString(number, precision, buffer, flags & ShouldTruncateTrailingZeros));
+
+ // Mimic String::format("%.[precision]f", ...), but use dtoas rounding facilities.
+ return String(numberToFixedWidthString(number, precision, buffer));
+}
+
+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, bool* didReadNumber) const
+{
+ if (!m_impl) {
+ if (ok)
+ *ok = false;
+ if (didReadNumber)
+ *didReadNumber = false;
+ return 0.0;
+ }
+ return m_impl->toDouble(ok, didReadNumber);
+}
+
+float String::toFloat(bool* ok, bool* didReadNumber) const
+{
+ if (!m_impl) {
+ if (ok)
+ *ok = false;
+ if (didReadNumber)
+ *didReadNumber = false;
+ return 0.0f;
+ }
+ return m_impl->toFloat(ok, didReadNumber);
+}
+
+String String::isolatedCopy() const
+{
+ if (!m_impl)
+ return String();
+ return m_impl->isolatedCopy();
+}
+
+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
+{
+ 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
+{
+ split(String(&separator, 1), false, result);
+}
+
+CString String::ascii() const
+{
+ // Printable ASCII characters 32..127 and the null character are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+
+ if (!length) {
+ char* characterBuffer;
+ return CString::newUninitialized(length, characterBuffer);
+ }
+
+ if (this->is8Bit()) {
+ const LChar* characters = this->characters8();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ LChar ch = characters[i];
+ characterBuffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch;
+ }
+
+ return result;
+ }
+
+ const UChar* characters = this->characters16();
+
+ 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();
+
+ if (!length)
+ return CString("", 0);
+
+ // 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();
+
+ if (is8Bit()) {
+ const LChar* characters = this->characters8();
+
+ ConversionResult result = convertLatin1ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size());
+ ASSERT_UNUSED(result, result != targetExhausted); // (length * 3) should be sufficient for any conversion
+ } else {
+ const UChar* characters = this->characters16();
+
+ 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 LChar* 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 = reinterpret_cast<const char*>(stringStart);
+ if (convertUTF8ToUTF16(&stringCurrent, reinterpret_cast<const char *>(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 LChar* string)
+{
+ if (!string)
+ return String();
+ return fromUTF8(string, strlen(reinterpret_cast<const char*>(string)));
+}
+
+String String::fromUTF8WithLatin1Fallback(const LChar* 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, typename CharType>
+static inline IntegralType toIntegralType(const CharType* 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;
+ CharType 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;
+}
+
+template <typename CharType>
+static unsigned lengthOfCharactersAsInteger(const CharType* 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 LChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<int, LChar>(data, length, ok, base);
+}
+
+int charactersToIntStrict(const UChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<int, UChar>(data, length, ok, base);
+}
+
+unsigned charactersToUIntStrict(const LChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<unsigned, LChar>(data, length, ok, base);
+}
+
+unsigned charactersToUIntStrict(const UChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<unsigned, UChar>(data, length, ok, base);
+}
+
+int64_t charactersToInt64Strict(const LChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<int64_t, LChar>(data, length, ok, base);
+}
+
+int64_t charactersToInt64Strict(const UChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<int64_t, UChar>(data, length, ok, base);
+}
+
+uint64_t charactersToUInt64Strict(const LChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<uint64_t, LChar>(data, length, ok, base);
+}
+
+uint64_t charactersToUInt64Strict(const UChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<uint64_t, UChar>(data, length, ok, base);
+}
+
+intptr_t charactersToIntPtrStrict(const LChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<intptr_t, LChar>(data, length, ok, base);
+}
+
+intptr_t charactersToIntPtrStrict(const UChar* data, size_t length, bool* ok, int base)
+{
+ return toIntegralType<intptr_t, UChar>(data, length, ok, base);
+}
+
+int charactersToInt(const LChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<int, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+}
+
+int charactersToInt(const UChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<int, UChar>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
+}
+
+unsigned charactersToUInt(const LChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<unsigned, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+}
+
+unsigned charactersToUInt(const UChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<unsigned, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+}
+
+int64_t charactersToInt64(const LChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<int64_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+}
+
+int64_t charactersToInt64(const UChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<int64_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+}
+
+uint64_t charactersToUInt64(const LChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<uint64_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+}
+
+uint64_t charactersToUInt64(const UChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<uint64_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+}
+
+intptr_t charactersToIntPtr(const LChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<intptr_t, LChar>(data, lengthOfCharactersAsInteger<LChar>(data, length), ok, 10);
+}
+
+intptr_t charactersToIntPtr(const UChar* data, size_t length, bool* ok)
+{
+ return toIntegralType<intptr_t, UChar>(data, lengthOfCharactersAsInteger<UChar>(data, length), ok, 10);
+}
+
+template <typename CharType>
+static inline double toDoubleType(const CharType* data, size_t length, bool* ok, bool* didReadNumber)
+{
+ if (!length) {
+ if (ok)
+ *ok = false;
+ if (didReadNumber)
+ *didReadNumber = 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* start = bytes.data();
+ char* end;
+ double val = WTF::strtod(start, &end);
+ if (ok)
+ *ok = (end == 0 || *end == '\0');
+ if (didReadNumber)
+ *didReadNumber = end - start;
+ return val;
+}
+
+double charactersToDouble(const LChar* data, size_t length, bool* ok, bool* didReadNumber)
+{
+ return toDoubleType<LChar>(data, length, ok, didReadNumber);
+}
+
+double charactersToDouble(const UChar* data, size_t length, bool* ok, bool* didReadNumber)
+{
+ return toDoubleType<UChar>(data, length, ok, didReadNumber);
+}
+
+float charactersToFloat(const LChar* data, size_t length, bool* ok, bool* didReadNumber)
+{
+ // FIXME: This will return ok even when the string fits into a double but not a float.
+ return static_cast<float>(toDoubleType<LChar>(data, length, ok, didReadNumber));
+}
+
+float charactersToFloat(const UChar* data, size_t length, bool* ok, bool* didReadNumber)
+{
+ // FIXME: This will return ok even when the string fits into a double but not a float.
+ return static_cast<float>(toDoubleType<UChar>(data, length, ok, didReadNumber));
+}
+
+const String& emptyString()
+{
+ DEFINE_STATIC_LOCAL(String, emptyString, (StringImpl::empty()));
+ return emptyString;
+}
+
+} // namespace WTF
+
+#ifndef NDEBUG
+// For use in the debugger
+String* string(const char*);
+Vector<char> asciiDebug(StringImpl* impl);
+Vector<char> asciiDebug(String& string);
+
+void String::show() const
+{
+ fprintf(stderr, "%s\n", asciiDebug(impl()).data());
+}
+
+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/Source/JavaScriptCore/wtf/text/WTFString.h b/Source/JavaScriptCore/wtf/text/WTFString.h
new file mode 100644
index 000000000..3cecc0afd
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/text/WTFString.h
@@ -0,0 +1,648 @@
+/*
+ * (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 "ASCIIFastPath.h"
+#include "StringImpl.h"
+
+#ifdef __OBJC__
+#include <objc/objc.h>
+#endif
+
+#if USE(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(BLACKBERRY)
+namespace BlackBerry {
+namespace WebKit {
+ class WebString;
+}
+}
+#endif
+
+namespace WTF {
+
+class CString;
+struct StringHash;
+
+// Declarations of string operations
+
+WTF_EXPORT_PRIVATE int charactersToIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10);
+WTF_EXPORT_PRIVATE int charactersToIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
+WTF_EXPORT_PRIVATE unsigned charactersToUIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10);
+WTF_EXPORT_PRIVATE unsigned charactersToUIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
+int64_t charactersToInt64Strict(const LChar*, 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 LChar*, 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 LChar*, size_t, bool* ok = 0, int base = 10);
+intptr_t charactersToIntPtrStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
+
+int charactersToInt(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage
+int charactersToInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
+unsigned charactersToUInt(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage
+unsigned charactersToUInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
+int64_t charactersToInt64(const LChar*, 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 LChar*, 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 LChar*, size_t, bool* ok = 0); // ignores trailing garbage
+intptr_t charactersToIntPtr(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
+
+WTF_EXPORT_PRIVATE double charactersToDouble(const LChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
+WTF_EXPORT_PRIVATE double charactersToDouble(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
+float charactersToFloat(const LChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
+float charactersToFloat(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
+
+enum FloatConversionFlags {
+ ShouldRoundSignificantFigures = 1 << 0,
+ ShouldRoundDecimalPlaces = 1 << 1,
+ ShouldTruncateTrailingZeros = 1 << 2
+};
+
+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.
+ WTF_EXPORT_PRIVATE String(const UChar* characters, unsigned length);
+
+ // Construct a string by copying the contents of a vector. To avoid
+ // copying, consider using String::adopt instead.
+ template<size_t inlineCapacity>
+ explicit String(const Vector<UChar, inlineCapacity>&);
+
+ // Construct a string with UTF-16 data, from a null-terminated source.
+ WTF_EXPORT_PRIVATE String(const UChar*);
+
+ // Construct a string with latin1 data.
+ WTF_EXPORT_PRIVATE String(const LChar* characters, unsigned length);
+ WTF_EXPORT_PRIVATE String(const char* characters, unsigned length);
+
+ // Construct a string with latin1 data, from a null-terminated source.
+ WTF_EXPORT_PRIVATE String(const LChar* characters);
+ WTF_EXPORT_PRIVATE 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<LChar>& buffer) { return StringImpl::adopt(buffer); }
+ static String adopt(StringBuffer<UChar>& 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();
+ }
+
+ const LChar* characters8() const
+ {
+ if (!m_impl)
+ return 0;
+ ASSERT(m_impl->is8Bit());
+ return m_impl->characters8();
+ }
+
+ const UChar* characters16() const
+ {
+ if (!m_impl)
+ return 0;
+ ASSERT(!m_impl->is8Bit());
+ return m_impl->characters16();
+ }
+
+ template <typename CharType>
+ inline const CharType* getCharacters() const;
+
+ bool is8Bit() const { return m_impl->is8Bit(); }
+
+ WTF_EXPORT_PRIVATE CString ascii() const;
+ WTF_EXPORT_PRIVATE CString latin1() const;
+ WTF_EXPORT_PRIVATE 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];
+ }
+
+ WTF_EXPORT_PRIVATE static String number(short);
+ WTF_EXPORT_PRIVATE static String number(unsigned short);
+ WTF_EXPORT_PRIVATE static String number(int);
+ WTF_EXPORT_PRIVATE static String number(unsigned);
+ WTF_EXPORT_PRIVATE static String number(long);
+ WTF_EXPORT_PRIVATE static String number(unsigned long);
+ WTF_EXPORT_PRIVATE static String number(long long);
+ WTF_EXPORT_PRIVATE static String number(unsigned long long);
+ WTF_EXPORT_PRIVATE static String number(double, unsigned = ShouldRoundSignificantFigures | ShouldTruncateTrailingZeros, unsigned precision = 6);
+
+ // 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 LChar* 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 LChar* 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 LChar* 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); }
+
+ WTF_EXPORT_PRIVATE const UChar* charactersWithNullTermination();
+
+ WTF_EXPORT_PRIVATE UChar32 characterStartingAt(unsigned) const; // Ditto.
+
+ bool contains(UChar c) const { return find(c) != notFound; }
+ bool contains(const LChar* 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(); }
+
+ WTF_EXPORT_PRIVATE void append(const String&);
+ WTF_EXPORT_PRIVATE void append(LChar);
+ void append(char c) { append(static_cast<LChar>(c)); };
+ WTF_EXPORT_PRIVATE void append(UChar);
+ WTF_EXPORT_PRIVATE void append(const UChar*, unsigned length);
+ WTF_EXPORT_PRIVATE 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 fill(UChar c) { if (m_impl) m_impl = m_impl->fill(c); }
+
+ WTF_EXPORT_PRIVATE void truncate(unsigned len);
+ WTF_EXPORT_PRIVATE void remove(unsigned pos, int len = 1);
+
+ WTF_EXPORT_PRIVATE 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
+ WTF_EXPORT_PRIVATE String lower() const;
+ WTF_EXPORT_PRIVATE String upper() const;
+
+ WTF_EXPORT_PRIVATE String stripWhiteSpace() const;
+ WTF_EXPORT_PRIVATE String stripWhiteSpace(IsWhiteSpaceFunctionPtr) const;
+ WTF_EXPORT_PRIVATE String simplifyWhiteSpace() const;
+ WTF_EXPORT_PRIVATE String simplifyWhiteSpace(IsWhiteSpaceFunctionPtr) const;
+
+ WTF_EXPORT_PRIVATE String removeCharacters(CharacterMatchFunctionPtr) const;
+ template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const;
+
+ // Return the string with case folded for case insensitive comparison.
+ WTF_EXPORT_PRIVATE String foldCase() const;
+
+#if !PLATFORM(QT)
+ WTF_EXPORT_PRIVATE static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
+#else
+ WTF_EXPORT_PRIVATE 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); }
+
+ WTF_EXPORT_PRIVATE void split(const String& separator, Vector<String>& result) const;
+ WTF_EXPORT_PRIVATE void split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const;
+ WTF_EXPORT_PRIVATE void split(UChar separator, Vector<String>& result) const;
+ WTF_EXPORT_PRIVATE void split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const;
+
+ WTF_EXPORT_PRIVATE int toIntStrict(bool* ok = 0, int base = 10) const;
+ WTF_EXPORT_PRIVATE unsigned toUIntStrict(bool* ok = 0, int base = 10) const;
+ WTF_EXPORT_PRIVATE int64_t toInt64Strict(bool* ok = 0, int base = 10) const;
+ WTF_EXPORT_PRIVATE uint64_t toUInt64Strict(bool* ok = 0, int base = 10) const;
+ WTF_EXPORT_PRIVATE intptr_t toIntPtrStrict(bool* ok = 0, int base = 10) const;
+
+ WTF_EXPORT_PRIVATE int toInt(bool* ok = 0) const;
+ WTF_EXPORT_PRIVATE unsigned toUInt(bool* ok = 0) const;
+ int64_t toInt64(bool* ok = 0) const;
+ WTF_EXPORT_PRIVATE uint64_t toUInt64(bool* ok = 0) const;
+ WTF_EXPORT_PRIVATE intptr_t toIntPtr(bool* ok = 0) const;
+ WTF_EXPORT_PRIVATE double toDouble(bool* ok = 0, bool* didReadNumber = 0) const;
+ WTF_EXPORT_PRIVATE float toFloat(bool* ok = 0, bool* didReadNumber = 0) const;
+
+ bool percentage(int& percentage) const;
+
+ WTF_EXPORT_PRIVATE String isolatedCopy() const;
+
+ // Prevent Strings from being implicitly convertable to bool as it will be ambiguous on any platform that
+ // allows implicit conversion to another pointer type (e.g., Mac allows implicit conversion to NSString*).
+ typedef struct ImplicitConversionFromWTFStringToBoolDisallowedA* (String::*UnspecifiedBoolTypeA);
+ typedef struct ImplicitConversionFromWTFStringToBoolDisallowedB* (String::*UnspecifiedBoolTypeB);
+ operator UnspecifiedBoolTypeA() const;
+ operator UnspecifiedBoolTypeB() const;
+
+#if USE(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)
+ WTF_EXPORT_PRIVATE String(const wxString&);
+ WTF_EXPORT_PRIVATE operator wxString() const;
+#endif
+
+#if PLATFORM(BLACKBERRY)
+ String(const BlackBerry::WebKit::WebString&);
+ operator BlackBerry::WebKit::WebString() const;
+#endif
+
+ // String::fromUTF8 will return a null string if
+ // the input data contains invalid UTF-8 sequences.
+ WTF_EXPORT_PRIVATE static String fromUTF8(const LChar*, size_t);
+ WTF_EXPORT_PRIVATE static String fromUTF8(const LChar*);
+ static String fromUTF8(const char* s, size_t length) { return fromUTF8(reinterpret_cast<const LChar*>(s), length); };
+ static String fromUTF8(const char* s) { return fromUTF8(reinterpret_cast<const LChar*>(s)); };
+
+ // 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.
+ WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(const LChar*, size_t);
+ static String fromUTF8WithLatin1Fallback(const char* s, size_t length) { return fromUTF8WithLatin1Fallback(reinterpret_cast<const LChar*>(s), length); };
+
+ // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
+ WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0) const
+ {
+ if (m_impl)
+ return m_impl->defaultWritingDirection(hasStrongDirectionality);
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = false;
+ return WTF::Unicode::LeftToRight;
+ }
+
+ bool containsOnlyASCII() const;
+ bool containsOnlyLatin1() const;
+ bool containsOnlyWhitespace() const { return !m_impl || m_impl->containsOnlyWhitespace(); }
+
+ // 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(); }
+
+#ifndef NDEBUG
+ void show() const;
+#endif
+
+private:
+ RefPtr<StringImpl> m_impl;
+};
+
+#if PLATFORM(QT)
+QDataStream& operator<<(QDataStream& stream, const String& str);
+QDataStream& operator>>(QDataStream& stream, String& str);
+#endif
+
+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 LChar* b) { return equal(a.impl(), b); }
+inline bool operator==(const String& a, const char* b) { return equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool operator==(const LChar* a, const String& b) { return equal(a, b.impl()); }
+inline bool operator==(const char* a, const String& b) { return equal(reinterpret_cast<const LChar*>(a), b.impl()); }
+template<size_t inlineCapacity>
+inline bool operator==(const Vector<char, inlineCapacity>& a, const String& b) { return equal(b.impl(), a.data(), a.size()); }
+template<size_t inlineCapacity>
+inline bool operator==(const String& a, const Vector<char, inlineCapacity>& b) { return b == a; }
+
+
+inline bool operator!=(const String& a, const String& b) { return !equal(a.impl(), b.impl()); }
+inline bool operator!=(const String& a, const LChar* b) { return !equal(a.impl(), b); }
+inline bool operator!=(const String& a, const char* b) { return !equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool operator!=(const LChar* a, const String& b) { return !equal(a, b.impl()); }
+inline bool operator!=(const char* a, const String& b) { return !equal(reinterpret_cast<const LChar*>(a), b.impl()); }
+template<size_t inlineCapacity>
+inline bool operator!=(const Vector<char, inlineCapacity>& a, const String& b) { return !(a == b); }
+template<size_t inlineCapacity>
+inline bool operator!=(const String& a, const Vector<char, inlineCapacity>& b) { return b != a; }
+
+inline bool equalIgnoringCase(const String& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); }
+inline bool equalIgnoringCase(const String& a, const LChar* b) { return equalIgnoringCase(a.impl(), b); }
+inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool equalIgnoringCase(const LChar* a, const String& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(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()); }
+
+template<size_t inlineCapacity>
+inline bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, const String& b) { return equalIgnoringNullity(a, 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
+
+template<size_t inlineCapacity>
+String::String(const Vector<UChar, inlineCapacity>& vector)
+ : m_impl(vector.size() ? StringImpl::create(vector.data(), vector.size()) : 0)
+{
+}
+
+template<>
+inline const LChar* String::getCharacters<LChar>() const
+{
+ ASSERT(is8Bit());
+ return characters8();
+}
+
+template<>
+inline const UChar* String::getCharacters<UChar>() const
+{
+ ASSERT(!is8Bit());
+ return characters16();
+}
+
+inline bool String::containsOnlyLatin1() const
+{
+ if (isEmpty())
+ return true;
+
+ if (is8Bit())
+ return true;
+
+ const UChar* characters = characters16();
+ UChar ored = 0;
+ for (size_t i = 0; i < m_impl->length(); ++i)
+ ored |= characters[i];
+ return !(ored & 0xFF00);
+}
+
+
+#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 String::containsOnlyASCII() const
+{
+ if (isEmpty())
+ return true;
+
+ if (is8Bit())
+ return charactersAreAllASCII(characters8(), m_impl->length());
+
+ return charactersAreAllASCII(characters16(), m_impl->length());
+}
+
+WTF_EXPORT_PRIVATE int codePointCompare(const String&, const String&);
+
+inline bool codePointCompareLessThan(const String& a, const String& b)
+{
+ return codePointCompare(a.impl(), b.impl()) < 0;
+}
+
+inline size_t find(const LChar* characters, unsigned length, LChar 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, UChar matchCharacter, unsigned index = 0)
+{
+ while (index < length) {
+ if (characters[index] == matchCharacter)
+ return index;
+ ++index;
+ }
+ return notFound;
+}
+
+inline size_t find(const LChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index = 0)
+{
+ while (index < length) {
+ if (matchFunction(characters[index]))
+ 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 LChar* characters, unsigned length, LChar 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 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 { };
+
+// Shared global empty string.
+WTF_EXPORT_PRIVATE const String& emptyString();
+
+}
+
+using WTF::CString;
+using WTF::String;
+using WTF::emptyString;
+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;
+using WTF::ShouldRoundDecimalPlaces;
+
+#include "AtomicString.h"
+#endif
diff --git a/Source/JavaScriptCore/wtf/threads/BinarySemaphore.cpp b/Source/JavaScriptCore/wtf/threads/BinarySemaphore.cpp
new file mode 100644
index 000000000..5f60aaf22
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/threads/BinarySemaphore.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "config.h"
+#include "BinarySemaphore.h"
+
+#if !PLATFORM(WIN)
+
+namespace WTF {
+
+BinarySemaphore::BinarySemaphore()
+ : m_isSet(false)
+{
+}
+
+BinarySemaphore::~BinarySemaphore()
+{
+}
+
+void BinarySemaphore::signal()
+{
+ MutexLocker locker(m_mutex);
+
+ m_isSet = true;
+ m_condition.signal();
+}
+
+bool BinarySemaphore::wait(double absoluteTime)
+{
+ MutexLocker locker(m_mutex);
+
+ bool timedOut = false;
+ while (!m_isSet) {
+ timedOut = !m_condition.timedWait(m_mutex, absoluteTime);
+ if (timedOut)
+ return false;
+ }
+
+ // Reset the semaphore.
+ m_isSet = false;
+ return true;
+}
+
+} // namespace WTF
+
+#endif // !PLATFORM(WIN)
diff --git a/Source/JavaScriptCore/wtf/threads/BinarySemaphore.h b/Source/JavaScriptCore/wtf/threads/BinarySemaphore.h
new file mode 100644
index 000000000..8e82207e9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/threads/BinarySemaphore.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010, 2011 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 BinarySemaphore_h
+#define BinarySemaphore_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadingPrimitives.h>
+
+namespace WTF {
+
+class BinarySemaphore {
+ WTF_MAKE_NONCOPYABLE(BinarySemaphore);
+
+public:
+ BinarySemaphore();
+ ~BinarySemaphore();
+
+ void signal();
+ bool wait(double absoluteTime);
+
+#if PLATFORM(WIN)
+ HANDLE event() const { return m_event; }
+#endif
+
+private:
+#if PLATFORM(WIN)
+ HANDLE m_event;
+#else
+ bool m_isSet;
+
+ Mutex m_mutex;
+ ThreadCondition m_condition;
+#endif
+};
+
+} // namespace WTF
+
+using WTF::BinarySemaphore;
+
+#endif // BinarySemaphore_h
diff --git a/Source/JavaScriptCore/wtf/threads/win/BinarySemaphoreWin.cpp b/Source/JavaScriptCore/wtf/threads/win/BinarySemaphoreWin.cpp
new file mode 100644
index 000000000..adc9e9b90
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/threads/win/BinarySemaphoreWin.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 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 "config.h"
+#include "BinarySemaphore.h"
+
+namespace WTF {
+
+BinarySemaphore::BinarySemaphore()
+ : m_event(::CreateEventW(0, FALSE, FALSE, 0))
+{
+}
+
+BinarySemaphore::~BinarySemaphore()
+{
+ ::CloseHandle(m_event);
+}
+
+void BinarySemaphore::signal()
+{
+ ::SetEvent(m_event);
+}
+
+bool BinarySemaphore::wait(double absoluteTime)
+{
+ DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
+ if (!interval) {
+ // Consider the wait to have timed out, even if the event has already been signaled, to
+ // match the WTF::ThreadCondition implementation.
+ return false;
+ }
+
+ DWORD result = ::WaitForSingleObjectEx(m_event, interval, FALSE);
+ switch (result) {
+ case WAIT_OBJECT_0:
+ // The event was signaled.
+ return true;
+
+ case WAIT_TIMEOUT:
+ // The wait timed out.
+ return false;
+
+ case WAIT_FAILED:
+ ASSERT_WITH_MESSAGE(false, "::WaitForSingleObjectEx failed with error %lu", ::GetLastError());
+ return false;
+ default:
+ ASSERT_WITH_MESSAGE(false, "::WaitForSingleObjectEx returned unexpected result %lu", result);
+ return false;
+ }
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/unicode/CharacterNames.h b/Source/JavaScriptCore/wtf/unicode/CharacterNames.h
new file mode 100644
index 000000000..10fdbf0ef
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/CharacterNames.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2007, 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 CharacterNames_h
+#define CharacterNames_h
+
+#include "Unicode.h"
+
+namespace WTF {
+namespace Unicode {
+
+// Names here are taken from the Unicode standard.
+
+// Most of these are UChar constants, not UChar32, which makes them
+// more convenient for WebCore code that mostly uses UTF-16.
+
+const UChar32 aegeanWordSeparatorLine = 0x10100;
+const UChar32 aegeanWordSeparatorDot = 0x10101;
+const UChar blackCircle = 0x25CF;
+const UChar blackSquare = 0x25A0;
+const UChar blackUpPointingTriangle = 0x25B2;
+const UChar bullet = 0x2022;
+const UChar bullseye = 0x25CE;
+const UChar carriageReturn = 0x000D;
+const UChar ethiopicPrefaceColon = 0x1366;
+const UChar ethiopicWordspace = 0x1361;
+const UChar fisheye = 0x25C9;
+const UChar hebrewPunctuationGeresh = 0x05F3;
+const UChar hebrewPunctuationGershayim = 0x05F4;
+const UChar horizontalEllipsis = 0x2026;
+const UChar hyphen = 0x2010;
+const UChar hyphenMinus = 0x002D;
+const UChar ideographicComma = 0x3001;
+const UChar ideographicFullStop = 0x3002;
+const UChar ideographicSpace = 0x3000;
+const UChar leftDoubleQuotationMark = 0x201C;
+const UChar leftSingleQuotationMark = 0x2018;
+const UChar leftToRightEmbed = 0x202A;
+const UChar leftToRightMark = 0x200E;
+const UChar leftToRightOverride = 0x202D;
+const UChar minusSign = 0x2212;
+const UChar newlineCharacter = 0x000A;
+const UChar noBreakSpace = 0x00A0;
+const UChar objectReplacementCharacter = 0xFFFC;
+const UChar popDirectionalFormatting = 0x202C;
+const UChar replacementCharacter = 0xFFFD;
+const UChar rightDoubleQuotationMark = 0x201D;
+const UChar rightSingleQuotationMark = 0x2019;
+const UChar rightToLeftEmbed = 0x202B;
+const UChar rightToLeftMark = 0x200F;
+const UChar rightToLeftOverride = 0x202E;
+const UChar sesameDot = 0xFE45;
+const UChar softHyphen = 0x00AD;
+const UChar space = 0x0020;
+const UChar tibetanMarkIntersyllabicTsheg = 0x0F0B;
+const UChar tibetanMarkDelimiterTshegBstar = 0x0F0C;
+const UChar32 ugariticWordDivider = 0x1039F;
+const UChar whiteBullet = 0x25E6;
+const UChar whiteCircle = 0x25CB;
+const UChar whiteSesameDot = 0xFE46;
+const UChar whiteUpPointingTriangle = 0x25B3;
+const UChar yenSign = 0x00A5;
+const UChar zeroWidthJoiner = 0x200D;
+const UChar zeroWidthNonJoiner = 0x200C;
+const UChar zeroWidthSpace = 0x200B;
+const UChar zeroWidthNoBreakSpace = 0xFEFF;
+
+} // namespace Unicode
+} // namespace WTF
+
+using WTF::Unicode::aegeanWordSeparatorLine;
+using WTF::Unicode::aegeanWordSeparatorDot;
+using WTF::Unicode::blackCircle;
+using WTF::Unicode::blackSquare;
+using WTF::Unicode::blackUpPointingTriangle;
+using WTF::Unicode::bullet;
+using WTF::Unicode::bullseye;
+using WTF::Unicode::carriageReturn;
+using WTF::Unicode::ethiopicPrefaceColon;
+using WTF::Unicode::ethiopicWordspace;
+using WTF::Unicode::fisheye;
+using WTF::Unicode::hebrewPunctuationGeresh;
+using WTF::Unicode::hebrewPunctuationGershayim;
+using WTF::Unicode::horizontalEllipsis;
+using WTF::Unicode::hyphen;
+using WTF::Unicode::hyphenMinus;
+using WTF::Unicode::ideographicComma;
+using WTF::Unicode::ideographicFullStop;
+using WTF::Unicode::ideographicSpace;
+using WTF::Unicode::leftDoubleQuotationMark;
+using WTF::Unicode::leftSingleQuotationMark;
+using WTF::Unicode::leftToRightEmbed;
+using WTF::Unicode::leftToRightMark;
+using WTF::Unicode::leftToRightOverride;
+using WTF::Unicode::minusSign;
+using WTF::Unicode::newlineCharacter;
+using WTF::Unicode::noBreakSpace;
+using WTF::Unicode::objectReplacementCharacter;
+using WTF::Unicode::popDirectionalFormatting;
+using WTF::Unicode::replacementCharacter;
+using WTF::Unicode::rightDoubleQuotationMark;
+using WTF::Unicode::rightSingleQuotationMark;
+using WTF::Unicode::rightToLeftEmbed;
+using WTF::Unicode::rightToLeftMark;
+using WTF::Unicode::rightToLeftOverride;
+using WTF::Unicode::sesameDot;
+using WTF::Unicode::softHyphen;
+using WTF::Unicode::space;
+using WTF::Unicode::tibetanMarkIntersyllabicTsheg;
+using WTF::Unicode::tibetanMarkDelimiterTshegBstar;
+using WTF::Unicode::ugariticWordDivider;
+using WTF::Unicode::whiteBullet;
+using WTF::Unicode::whiteCircle;
+using WTF::Unicode::whiteSesameDot;
+using WTF::Unicode::whiteUpPointingTriangle;
+using WTF::Unicode::yenSign;
+using WTF::Unicode::zeroWidthJoiner;
+using WTF::Unicode::zeroWidthNonJoiner;
+using WTF::Unicode::zeroWidthSpace;
+using WTF::Unicode::zeroWidthNoBreakSpace;
+
+#endif // CharacterNames_h
diff --git a/Source/JavaScriptCore/wtf/unicode/Collator.h b/Source/JavaScriptCore/wtf/unicode/Collator.h
new file mode 100644
index 000000000..00ab16e6a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/Collator.h
@@ -0,0 +1,69 @@
+/*
+ * 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 WTF_Collator_h
+#define WTF_Collator_h
+
+#include <wtf/FastAllocBase.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+struct UCollator;
+#endif
+
+namespace WTF {
+
+ class Collator {
+ WTF_MAKE_NONCOPYABLE(Collator); WTF_MAKE_FAST_ALLOCATED;
+ public:
+ enum Result { Equal = 0, Greater = 1, Less = -1 };
+
+ Collator(const char* locale); // Parsing is lenient; e.g. language identifiers (such as "en-US") are accepted, too.
+ ~Collator();
+ void setOrderLowerFirst(bool);
+
+ static PassOwnPtr<Collator> userDefault();
+
+ Result collate(const ::UChar*, size_t, const ::UChar*, size_t) const;
+
+ private:
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+ void createCollator() const;
+ void releaseCollator();
+ mutable UCollator* m_collator;
+#endif
+ char* m_locale;
+ bool m_lowerFirst;
+ };
+}
+
+using WTF::Collator;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp b/Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp
new file mode 100644
index 000000000..7bde114a4
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "Collator.h"
+
+#if !USE(ICU_UNICODE) || UCONFIG_NO_COLLATION
+
+namespace WTF {
+
+Collator::Collator(const char*)
+{
+}
+
+Collator::~Collator()
+{
+}
+
+void Collator::setOrderLowerFirst(bool)
+{
+}
+
+PassOwnPtr<Collator> Collator::userDefault()
+{
+ return adoptPtr(new Collator(0));
+}
+
+// A default implementation for platforms that lack Unicode-aware collation.
+Collator::Result Collator::collate(const UChar* lhs, size_t lhsLength, const UChar* rhs, size_t rhsLength) const
+{
+ int lmin = lhsLength < rhsLength ? lhsLength : rhsLength;
+ int l = 0;
+ while (l < lmin && *lhs == *rhs) {
+ lhs++;
+ rhs++;
+ l++;
+ }
+
+ if (l < lmin)
+ return (*lhs > *rhs) ? Greater : Less;
+
+ if (lhsLength == rhsLength)
+ return Equal;
+
+ return (lhsLength > rhsLength) ? Greater : Less;
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/unicode/ScriptCodesFromICU.h b/Source/JavaScriptCore/wtf/unicode/ScriptCodesFromICU.h
new file mode 100644
index 000000000..4760399a1
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/ScriptCodesFromICU.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1997-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ */
+
+#ifndef WTF_ScriptCodesFromICU_h
+#define WTF_ScriptCodesFromICU_h
+
+/**
+ * Constants for ISO 15924 script codes.
+ *
+ * Many of these script codes - those from Unicode's ScriptNames.txt -
+ * are character property values for Unicode's Script property.
+ * See UAX #24 Script Names (http://www.unicode.org/reports/tr24/).
+ *
+ * Starting with ICU 3.6, constants for most ISO 15924 script codes
+ * are included (currently excluding private-use codes Qaaa..Qabx).
+ * For scripts for which there are codes in ISO 15924 but which are not
+ * used in the Unicode Character Database (UCD), there are no Unicode characters
+ * associated with those scripts.
+ *
+ * For example, there are no characters that have a UCD script code of
+ * Hans or Hant. All Han ideographs have the Hani script code.
+ * The Hans and Hant script codes are used with CLDR data.
+ *
+ * ISO 15924 script codes are included for use with CLDR and similar.
+ *
+ * @stable ICU 2.2
+ */
+typedef enum UScriptCode {
+ USCRIPT_INVALID_CODE = -1,
+ USCRIPT_COMMON = 0 , /* Zyyy */
+ USCRIPT_INHERITED = 1, /* Qaai */
+ USCRIPT_ARABIC = 2, /* Arab */
+ USCRIPT_ARMENIAN = 3, /* Armn */
+ USCRIPT_BENGALI = 4, /* Beng */
+ USCRIPT_BOPOMOFO = 5, /* Bopo */
+ USCRIPT_CHEROKEE = 6, /* Cher */
+ USCRIPT_COPTIC = 7, /* Copt */
+ USCRIPT_CYRILLIC = 8, /* Cyrl */
+ USCRIPT_DESERET = 9, /* Dsrt */
+ USCRIPT_DEVANAGARI = 10, /* Deva */
+ USCRIPT_ETHIOPIC = 11, /* Ethi */
+ USCRIPT_GEORGIAN = 12, /* Geor */
+ USCRIPT_GOTHIC = 13, /* Goth */
+ USCRIPT_GREEK = 14, /* Grek */
+ USCRIPT_GUJARATI = 15, /* Gujr */
+ USCRIPT_GURMUKHI = 16, /* Guru */
+ USCRIPT_HAN = 17, /* Hani */
+ USCRIPT_HANGUL = 18, /* Hang */
+ USCRIPT_HEBREW = 19, /* Hebr */
+ USCRIPT_HIRAGANA = 20, /* Hira */
+ USCRIPT_KANNADA = 21, /* Knda */
+ USCRIPT_KATAKANA = 22, /* Kana */
+ USCRIPT_KHMER = 23, /* Khmr */
+ USCRIPT_LAO = 24, /* Laoo */
+ USCRIPT_LATIN = 25, /* Latn */
+ USCRIPT_MALAYALAM = 26, /* Mlym */
+ USCRIPT_MONGOLIAN = 27, /* Mong */
+ USCRIPT_MYANMAR = 28, /* Mymr */
+ USCRIPT_OGHAM = 29, /* Ogam */
+ USCRIPT_OLD_ITALIC = 30, /* Ital */
+ USCRIPT_ORIYA = 31, /* Orya */
+ USCRIPT_RUNIC = 32, /* Runr */
+ USCRIPT_SINHALA = 33, /* Sinh */
+ USCRIPT_SYRIAC = 34, /* Syrc */
+ USCRIPT_TAMIL = 35, /* Taml */
+ USCRIPT_TELUGU = 36, /* Telu */
+ USCRIPT_THAANA = 37, /* Thaa */
+ USCRIPT_THAI = 38, /* Thai */
+ USCRIPT_TIBETAN = 39, /* Tibt */
+ /** Canadian_Aboriginal script. @stable ICU 2.6 */
+ USCRIPT_CANADIAN_ABORIGINAL = 40, /* Cans */
+ /** Canadian_Aboriginal script (alias). @stable ICU 2.2 */
+ USCRIPT_UCAS = USCRIPT_CANADIAN_ABORIGINAL,
+ USCRIPT_YI = 41, /* Yiii */
+ USCRIPT_TAGALOG = 42, /* Tglg */
+ USCRIPT_HANUNOO = 43, /* Hano */
+ USCRIPT_BUHID = 44, /* Buhd */
+ USCRIPT_TAGBANWA = 45, /* Tagb */
+
+ /* New scripts in Unicode 4 @stable ICU 2.6 */
+ USCRIPT_BRAILLE = 46, /* Brai */
+ USCRIPT_CYPRIOT = 47, /* Cprt */
+ USCRIPT_LIMBU = 48, /* Limb */
+ USCRIPT_LINEAR_B = 49, /* Linb */
+ USCRIPT_OSMANYA = 50, /* Osma */
+ USCRIPT_SHAVIAN = 51, /* Shaw */
+ USCRIPT_TAI_LE = 52, /* Tale */
+ USCRIPT_UGARITIC = 53, /* Ugar */
+
+ /** New script code in Unicode 4.0.1 @stable ICU 3.0 */
+ USCRIPT_KATAKANA_OR_HIRAGANA = 54,/*Hrkt */
+
+#ifndef U_HIDE_DRAFT_API
+ /* New scripts in Unicode 4.1 @draft ICU 3.4 */
+ USCRIPT_BUGINESE = 55, /* Bugi */
+ USCRIPT_GLAGOLITIC = 56, /* Glag */
+ USCRIPT_KHAROSHTHI = 57, /* Khar */
+ USCRIPT_SYLOTI_NAGRI = 58, /* Sylo */
+ USCRIPT_NEW_TAI_LUE = 59, /* Talu */
+ USCRIPT_TIFINAGH = 60, /* Tfng */
+ USCRIPT_OLD_PERSIAN = 61, /* Xpeo */
+
+ /* New script codes from ISO 15924 @draft ICU 3.6 */
+ USCRIPT_BALINESE = 62, /* Bali */
+ USCRIPT_BATAK = 63, /* Batk */
+ USCRIPT_BLISSYMBOLS = 64, /* Blis */
+ USCRIPT_BRAHMI = 65, /* Brah */
+ USCRIPT_CHAM = 66, /* Cham */
+ USCRIPT_CIRTH = 67, /* Cirt */
+ USCRIPT_OLD_CHURCH_SLAVONIC_CYRILLIC = 68, /* Cyrs */
+ USCRIPT_DEMOTIC_EGYPTIAN = 69, /* Egyd */
+ USCRIPT_HIERATIC_EGYPTIAN = 70, /* Egyh */
+ USCRIPT_EGYPTIAN_HIEROGLYPHS = 71, /* Egyp */
+ USCRIPT_KHUTSURI = 72, /* Geok */
+ USCRIPT_SIMPLIFIED_HAN = 73, /* Hans */
+ USCRIPT_TRADITIONAL_HAN = 74, /* Hant */
+ USCRIPT_PAHAWH_HMONG = 75, /* Hmng */
+ USCRIPT_OLD_HUNGARIAN = 76, /* Hung */
+ USCRIPT_HARAPPAN_INDUS = 77, /* Inds */
+ USCRIPT_JAVANESE = 78, /* Java */
+ USCRIPT_KAYAH_LI = 79, /* Kali */
+ USCRIPT_LATIN_FRAKTUR = 80, /* Latf */
+ USCRIPT_LATIN_GAELIC = 81, /* Latg */
+ USCRIPT_LEPCHA = 82, /* Lepc */
+ USCRIPT_LINEAR_A = 83, /* Lina */
+ USCRIPT_MANDAEAN = 84, /* Mand */
+ USCRIPT_MAYAN_HIEROGLYPHS = 85, /* Maya */
+ USCRIPT_MEROITIC = 86, /* Mero */
+ USCRIPT_NKO = 87, /* Nkoo */
+ USCRIPT_ORKHON = 88, /* Orkh */
+ USCRIPT_OLD_PERMIC = 89, /* Perm */
+ USCRIPT_PHAGS_PA = 90, /* Phag */
+ USCRIPT_PHOENICIAN = 91, /* Phnx */
+ USCRIPT_PHONETIC_POLLARD = 92, /* Plrd */
+ USCRIPT_RONGORONGO = 93, /* Roro */
+ USCRIPT_SARATI = 94, /* Sara */
+ USCRIPT_ESTRANGELO_SYRIAC = 95, /* Syre */
+ USCRIPT_WESTERN_SYRIAC = 96, /* Syrj */
+ USCRIPT_EASTERN_SYRIAC = 97, /* Syrn */
+ USCRIPT_TENGWAR = 98, /* Teng */
+ USCRIPT_VAI = 99, /* Vaii */
+ USCRIPT_VISIBLE_SPEECH = 100, /* Visp */
+ USCRIPT_CUNEIFORM = 101,/* Xsux */
+ USCRIPT_UNWRITTEN_LANGUAGES = 102,/* Zxxx */
+ USCRIPT_UNKNOWN = 103,/* Zzzz */ /* Unknown="Code for uncoded script", for unassigned code points */
+ /* Private use codes from Qaaa - Qabx are not supported*/
+#endif /* U_HIDE_DRAFT_API */
+ USCRIPT_CODE_LIMIT = 104
+} UScriptCode;
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/unicode/UTF8.cpp b/Source/JavaScriptCore/wtf/unicode/UTF8.cpp
new file mode 100644
index 000000000..8ea5c6992
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/UTF8.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.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.
+ *
+ * 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 "UTF8.h"
+
+#include "ASCIICType.h"
+#include <wtf/StringHasher.h>
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WTF {
+namespace Unicode {
+
+inline int inlineUTF8SequenceLengthNonASCII(char b0)
+{
+ if ((b0 & 0xC0) != 0xC0)
+ return 0;
+ if ((b0 & 0xE0) == 0xC0)
+ return 2;
+ if ((b0 & 0xF0) == 0xE0)
+ return 3;
+ if ((b0 & 0xF8) == 0xF0)
+ return 4;
+ return 0;
+}
+
+inline int inlineUTF8SequenceLength(char b0)
+{
+ return isASCII(b0) ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
+}
+
+int UTF8SequenceLength(char b0)
+{
+ return isASCII(b0) ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
+}
+
+int decodeUTF8Sequence(const char* sequence)
+{
+ // Handle 0-byte sequences (never valid).
+ const unsigned char b0 = sequence[0];
+ const int length = inlineUTF8SequenceLength(b0);
+ if (length == 0)
+ return -1;
+
+ // Handle 1-byte sequences (plain ASCII).
+ const unsigned char b1 = sequence[1];
+ if (length == 1) {
+ if (b1)
+ return -1;
+ return b0;
+ }
+
+ // Handle 2-byte sequences.
+ if ((b1 & 0xC0) != 0x80)
+ return -1;
+ const unsigned char b2 = sequence[2];
+ if (length == 2) {
+ if (b2)
+ return -1;
+ const int c = ((b0 & 0x1F) << 6) | (b1 & 0x3F);
+ if (c < 0x80)
+ return -1;
+ return c;
+ }
+
+ // Handle 3-byte sequences.
+ if ((b2 & 0xC0) != 0x80)
+ return -1;
+ const unsigned char b3 = sequence[3];
+ if (length == 3) {
+ if (b3)
+ return -1;
+ const int c = ((b0 & 0xF) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);
+ if (c < 0x800)
+ return -1;
+ // UTF-16 surrogates should never appear in UTF-8 data.
+ if (c >= 0xD800 && c <= 0xDFFF)
+ return -1;
+ return c;
+ }
+
+ // Handle 4-byte sequences.
+ if ((b3 & 0xC0) != 0x80)
+ return -1;
+ const unsigned char b4 = sequence[4];
+ if (length == 4) {
+ if (b4)
+ return -1;
+ const int c = ((b0 & 0x7) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F);
+ if (c < 0x10000 || c > 0x10FFFF)
+ return -1;
+ return c;
+ }
+
+ return -1;
+}
+
+// Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+// into the first byte, depending on how many bytes follow. There are
+// as many entries in this table as there are UTF-8 sequence types.
+// (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+// for *legal* UTF-8 will be 4 or fewer bytes total.
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ConversionResult convertLatin1ToUTF8(
+ const LChar** sourceStart, const LChar* sourceEnd,
+ char** targetStart, char* targetEnd)
+{
+ ConversionResult result = conversionOK;
+ const LChar* source = *sourceStart;
+ char* target = *targetStart;
+ while (source < sourceEnd) {
+ UChar32 ch;
+ unsigned short bytesToWrite = 0;
+ const UChar32 byteMask = 0xBF;
+ const UChar32 byteMark = 0x80;
+ const LChar* oldSource = source; // In case we have to back up because of target overflow.
+ ch = static_cast<unsigned short>(*source++);
+
+ // Figure out how many bytes the result will require
+ if (ch < (UChar32)0x80)
+ bytesToWrite = 1;
+ else
+ bytesToWrite = 2;
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; // Back up source pointer!
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { // note: everything falls through.
+ case 2:
+ *--target = (char)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 1:
+ *--target = (char)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+ConversionResult convertUTF16ToUTF8(
+ const UChar** sourceStart, const UChar* sourceEnd,
+ char** targetStart, char* targetEnd, bool strict)
+{
+ ConversionResult result = conversionOK;
+ const UChar* source = *sourceStart;
+ char* target = *targetStart;
+ while (source < sourceEnd) {
+ UChar32 ch;
+ unsigned short bytesToWrite = 0;
+ const UChar32 byteMask = 0xBF;
+ const UChar32 byteMark = 0x80;
+ const UChar* oldSource = source; // In case we have to back up because of target overflow.
+ ch = static_cast<unsigned short>(*source++);
+ // If we have a surrogate pair, convert to UChar32 first.
+ if (ch >= 0xD800 && ch <= 0xDBFF) {
+ // If the 16 bits following the high surrogate are in the source buffer...
+ if (source < sourceEnd) {
+ UChar32 ch2 = static_cast<unsigned short>(*source);
+ // If it's a low surrogate, convert to UChar32.
+ if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
+ ch = ((ch - 0xD800) << 10) + (ch2 - 0xDC00) + 0x0010000;
+ ++source;
+ } else if (strict) { // it's an unpaired high surrogate
+ --source; // return to the illegal value itself
+ result = sourceIllegal;
+ break;
+ }
+ } else { // We don't have the 16 bits following the high surrogate.
+ --source; // return to the high surrogate
+ result = sourceExhausted;
+ break;
+ }
+ } else if (strict) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (ch >= 0xDC00 && ch <= 0xDFFF) {
+ --source; // return to the illegal value itself
+ result = sourceIllegal;
+ break;
+ }
+ }
+ // Figure out how many bytes the result will require
+ if (ch < (UChar32)0x80) {
+ bytesToWrite = 1;
+ } else if (ch < (UChar32)0x800) {
+ bytesToWrite = 2;
+ } else if (ch < (UChar32)0x10000) {
+ bytesToWrite = 3;
+ } else if (ch < (UChar32)0x110000) {
+ bytesToWrite = 4;
+ } else {
+ bytesToWrite = 3;
+ ch = replacementCharacter;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; // Back up source pointer!
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { // note: everything falls through.
+ case 4: *--target = (char)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (char)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (char)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (char)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+// This must be called with the length pre-determined by the first byte.
+// If presented with a length > 4, this returns false. The Unicode
+// definition of UTF-8 goes up to 4-byte sequences.
+static bool isLegalUTF8(const unsigned char* source, int length)
+{
+ unsigned char a;
+ const unsigned char* srcptr = source + length;
+ switch (length) {
+ default: return false;
+ // Everything else falls through when "true"...
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ // no fall-through in this inner switch
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4)
+ return false;
+ return true;
+}
+
+// Magic values subtracted from a buffer value during UTF8 conversion.
+// This table contains as many values as there might be trailing bytes
+// in a UTF-8 sequence.
+static const UChar32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+static inline UChar32 readUTF8Sequence(const char*& sequence, unsigned length)
+{
+ UChar32 character = 0;
+
+ // The cases all fall through.
+ switch (length) {
+ case 6: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 5: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 4: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 3: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 2: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 1: character += static_cast<unsigned char>(*sequence++);
+ }
+
+ return character - offsetsFromUTF8[length - 1];
+}
+
+ConversionResult convertUTF8ToUTF16(
+ const char** sourceStart, const char* sourceEnd,
+ UChar** targetStart, UChar* targetEnd, bool strict)
+{
+ ConversionResult result = conversionOK;
+ const char* source = *sourceStart;
+ UChar* target = *targetStart;
+ while (source < sourceEnd) {
+ int utf8SequenceLength = inlineUTF8SequenceLength(*source);
+ if (sourceEnd - source < utf8SequenceLength) {
+ result = sourceExhausted;
+ break;
+ }
+ // Do this check whether lenient or strict
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(source), utf8SequenceLength)) {
+ result = sourceIllegal;
+ break;
+ }
+
+ UChar32 character = readUTF8Sequence(source, utf8SequenceLength);
+
+ if (target >= targetEnd) {
+ source -= utf8SequenceLength; // Back up source pointer!
+ result = targetExhausted;
+ break;
+ }
+
+ if (U_IS_BMP(character)) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (U_IS_SURROGATE(character)) {
+ if (strict) {
+ source -= utf8SequenceLength; // return to the illegal value itself
+ result = sourceIllegal;
+ break;
+ } else
+ *target++ = replacementCharacter;
+ } else
+ *target++ = character; // normal case
+ } else if (U_IS_SUPPLEMENTARY(character)) {
+ // target is a character in range 0xFFFF - 0x10FFFF
+ if (target + 1 >= targetEnd) {
+ source -= utf8SequenceLength; // Back up source pointer!
+ result = targetExhausted;
+ break;
+ }
+ *target++ = U16_LEAD(character);
+ *target++ = U16_TRAIL(character);
+ } else {
+ if (strict) {
+ source -= utf8SequenceLength; // return to the start
+ result = sourceIllegal;
+ break; // Bail out; shouldn't continue
+ } else
+ *target++ = replacementCharacter;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+unsigned calculateStringHashAndLengthFromUTF8(const char* data, const char* dataEnd, unsigned& dataLength, unsigned& utf16Length)
+{
+ if (!data)
+ return 0;
+
+ StringHasher stringHasher;
+ dataLength = 0;
+ utf16Length = 0;
+
+ while (data < dataEnd || (!dataEnd && *data)) {
+ if (isASCII(*data)) {
+ stringHasher.addCharacter(*data++);
+ dataLength++;
+ utf16Length++;
+ continue;
+ }
+
+ int utf8SequenceLength = inlineUTF8SequenceLengthNonASCII(*data);
+ dataLength += utf8SequenceLength;
+
+ if (!dataEnd) {
+ for (int i = 1; i < utf8SequenceLength; ++i) {
+ if (!data[i])
+ return 0;
+ }
+ } else if (dataEnd - data < utf8SequenceLength)
+ return 0;
+
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(data), utf8SequenceLength))
+ return 0;
+
+ UChar32 character = readUTF8Sequence(data, utf8SequenceLength);
+ ASSERT(!isASCII(character));
+
+ if (U_IS_BMP(character)) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (U_IS_SURROGATE(character))
+ return 0;
+ stringHasher.addCharacter(static_cast<UChar>(character)); // normal case
+ utf16Length++;
+ } else if (U_IS_SUPPLEMENTARY(character)) {
+ stringHasher.addCharacters(static_cast<UChar>(U16_LEAD(character)),
+ static_cast<UChar>(U16_TRAIL(character)));
+ utf16Length += 2;
+ } else
+ return 0;
+ }
+
+ return stringHasher.hash();
+}
+
+bool equalUTF16WithUTF8(const UChar* a, const UChar* aEnd, const char* b, const char* bEnd)
+{
+ while (b < bEnd) {
+ if (isASCII(*b)) {
+ if (*a++ != *b++)
+ return false;
+ continue;
+ }
+
+ int utf8SequenceLength = inlineUTF8SequenceLengthNonASCII(*b);
+
+ if (bEnd - b < utf8SequenceLength)
+ return false;
+
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(b), utf8SequenceLength))
+ return 0;
+
+ UChar32 character = readUTF8Sequence(b, utf8SequenceLength);
+ ASSERT(!isASCII(character));
+
+ if (U_IS_BMP(character)) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (U_IS_SURROGATE(character))
+ return false;
+ if (*a++ != character)
+ return false;
+ } else if (U_IS_SUPPLEMENTARY(character)) {
+ if (*a++ != U16_LEAD(character))
+ return false;
+ if (*a++ != U16_TRAIL(character))
+ return false;
+ } else
+ return false;
+ }
+
+ return a == aEnd;
+}
+
+} // namespace Unicode
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/unicode/UTF8.h b/Source/JavaScriptCore/wtf/unicode/UTF8.h
new file mode 100644
index 000000000..bd3dd8a0a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/UTF8.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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_UTF8_h
+#define WTF_UTF8_h
+
+#include "Unicode.h"
+
+namespace WTF {
+namespace Unicode {
+
+ // Given a first byte, gives the length of the UTF-8 sequence it begins.
+ // Returns 0 for bytes that are not legal starts of UTF-8 sequences.
+ // Only allows sequences of up to 4 bytes, since that works for all Unicode characters (U-00000000 to U-0010FFFF).
+ int UTF8SequenceLength(char);
+
+ // Takes a null-terminated C-style string with a UTF-8 sequence in it and converts it to a character.
+ // Only allows Unicode characters (U-00000000 to U-0010FFFF).
+ // Returns -1 if the sequence is not valid (including presence of extra bytes).
+ int decodeUTF8Sequence(const char*);
+
+ typedef enum {
+ conversionOK, // conversion successful
+ sourceExhausted, // partial character in source, but hit end
+ targetExhausted, // insuff. room in target for conversion
+ sourceIllegal // source sequence is illegal/malformed
+ } ConversionResult;
+
+ // These conversion functions take a "strict" argument. When this
+ // flag is set to strict, both irregular sequences and isolated surrogates
+ // will cause an error. When the flag is set to lenient, both irregular
+ // sequences and isolated surrogates are converted.
+ //
+ // Whether the flag is strict or lenient, all illegal sequences will cause
+ // an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ // or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ // must check for illegal sequences.
+ //
+ // When the flag is set to lenient, characters over 0x10FFFF are converted
+ // to the replacement character; otherwise (when the flag is set to strict)
+ // they constitute an error.
+
+ ConversionResult convertUTF8ToUTF16(
+ const char** sourceStart, const char* sourceEnd,
+ UChar** targetStart, UChar* targetEnd, bool strict = true);
+
+ ConversionResult convertLatin1ToUTF8(
+ const LChar** sourceStart, const LChar* sourceEnd,
+ char** targetStart, char* targetEnd);
+
+ ConversionResult convertUTF16ToUTF8(
+ const UChar** sourceStart, const UChar* sourceEnd,
+ char** targetStart, char* targetEnd, bool strict = true);
+
+ unsigned calculateStringHashAndLengthFromUTF8(const char* data, const char* dataEnd, unsigned& dataLength, unsigned& utf16Length);
+
+ bool equalUTF16WithUTF8(const UChar* a, const UChar* aEnd, const char* b, const char* bEnd);
+
+} // namespace Unicode
+} // namespace WTF
+
+#endif // WTF_UTF8_h
diff --git a/Source/JavaScriptCore/wtf/unicode/Unicode.h b/Source/JavaScriptCore/wtf/unicode/Unicode.h
new file mode 100644
index 000000000..cc44476a6
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/Unicode.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006, 2008, 2009 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.
+ *
+ */
+
+#ifndef WTF_UNICODE_H
+#define WTF_UNICODE_H
+
+#include <wtf/Assertions.h>
+
+// Define platform neutral 8 bit character type (L is for Latin-1).
+typedef unsigned char LChar;
+
+#if USE(QT4_UNICODE)
+#include "qt4/UnicodeQt4.h"
+#elif USE(ICU_UNICODE)
+#include <wtf/unicode/icu/UnicodeIcu.h>
+#elif USE(GLIB_UNICODE)
+#include <wtf/unicode/glib/UnicodeGLib.h>
+#elif USE(WINCE_UNICODE)
+#include <wtf/unicode/wince/UnicodeWinCE.h>
+#else
+#error "Unknown Unicode implementation"
+#endif
+
+COMPILE_ASSERT(sizeof(UChar) == 2, UCharIsTwoBytes);
+
+#endif // WTF_UNICODE_H
diff --git a/Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h b/Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h
new file mode 100644
index 000000000..09a7036e3
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1999-2004, International Business Machines Corporation and others. All Rights Reserved.
+ *
+ */
+
+#ifndef UnicodeMacrosFromICU_h
+#define UnicodeMacrosFromICU_h
+
+// 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)
+#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 U16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2)
+
+#define U_IS_SUPPLEMENTARY(c) ((UChar32)((c)-0x10000)<=0xfffff)
+#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_GET(s, start, i, length, c) { \
+ (c)=(s)[i]; \
+ if(U16_IS_SURROGATE(c)) { \
+ uint16_t __c2; \
+ if(U16_IS_SURROGATE_LEAD(c)) { \
+ if((i)+1<(length) && U16_IS_TRAIL(__c2=(s)[(i)+1])) { \
+ (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } else { \
+ if((i)-1>=(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
+ (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+ } \
+ } \
+ } \
+}
+
+#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_BACK_1(s, start, i) { \
+ if(U16_IS_TRAIL((s)[--(i)]) && (i)>(start) && U16_IS_LEAD((s)[(i)-1])) { \
+ --(i); \
+ } \
+}
+
+#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_FWD_1(s, i, length) { \
+ if(U16_IS_LEAD((s)[(i)++]) && (i)<(length) && U16_IS_TRAIL((s)[i])) { \
+ ++(i); \
+ } \
+}
+
+#define U_MASK(x) ((uint32_t)1<<(x))
+
+#define U8_MAX_LENGTH 4
+
+#define U8_APPEND_UNSAFE(s, i, c) { \
+ if((uint32_t)(c)<=0x7f) { \
+ (s)[(i)++]=(uint8_t)(c); \
+ } else { \
+ if((uint32_t)(c)<=0x7ff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+ } else { \
+ if((uint32_t)(c)<=0xffff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+ } else { \
+ (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
+ (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+ } \
+}
+#endif
diff --git a/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp b/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp
new file mode 100644
index 000000000..a01c3ee9d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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
+ * 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 "UnicodeGLib.h"
+
+#include <wtf/Vector.h>
+#include <wtf/unicode/UTF8.h>
+
+#define UTF8_IS_SURROGATE(character) (character >= 0x10000 && character <= 0x10FFFF)
+
+namespace WTF {
+namespace Unicode {
+
+UChar32 foldCase(UChar32 ch)
+{
+ GOwnPtr<GError> gerror;
+
+ GOwnPtr<char> utf8char;
+ utf8char.set(g_ucs4_to_utf8(reinterpret_cast<gunichar*>(&ch), 1, 0, 0, &gerror.outPtr()));
+ if (gerror)
+ return ch;
+
+ GOwnPtr<char> utf8caseFolded;
+ utf8caseFolded.set(g_utf8_casefold(utf8char.get(), -1));
+
+ GOwnPtr<gunichar> ucs4Result;
+ ucs4Result.set(g_utf8_to_ucs4_fast(utf8caseFolded.get(), -1, 0));
+
+ return *ucs4Result;
+}
+
+static int getUTF16LengthFromUTF8(const gchar* utf8String, int length)
+{
+ int utf16Length = 0;
+ const gchar* inputString = utf8String;
+
+ while ((utf8String + length - inputString > 0) && *inputString) {
+ gunichar character = g_utf8_get_char(inputString);
+
+ utf16Length += UTF8_IS_SURROGATE(character) ? 2 : 1;
+ inputString = g_utf8_next_char(inputString);
+ }
+
+ return utf16Length;
+}
+
+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;
+
+ // 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(caseFunction(buffer.data(), buffer.size()));
+ long utf8ResultLength = strlen(utf8Result.get());
+
+ // Calculate the destination buffer size.
+ int realLength = getUTF16LengthFromUTF8(utf8Result.get(), utf8ResultLength);
+ if (realLength > resultLength) {
+ *error = true;
+ return realLength;
+ }
+
+ // 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 <= 0 ? -1 : utf16ResultLength;
+}
+int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ return convertCase(result, resultLength, src, srcLength, error, g_utf8_casefold);
+}
+
+int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ return convertCase(result, resultLength, src, srcLength, error, g_utf8_strdown);
+}
+
+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)
+{
+ PangoBidiType type = pango_bidi_type_for_unichar(c);
+ switch (type) {
+ case PANGO_BIDI_TYPE_L:
+ return LeftToRight;
+ case PANGO_BIDI_TYPE_R:
+ return RightToLeft;
+ case PANGO_BIDI_TYPE_AL:
+ return RightToLeftArabic;
+ case PANGO_BIDI_TYPE_LRE:
+ return LeftToRightEmbedding;
+ case PANGO_BIDI_TYPE_RLE:
+ return RightToLeftEmbedding;
+ case PANGO_BIDI_TYPE_LRO:
+ return LeftToRightOverride;
+ case PANGO_BIDI_TYPE_RLO:
+ return RightToLeftOverride;
+ case PANGO_BIDI_TYPE_PDF:
+ return PopDirectionalFormat;
+ case PANGO_BIDI_TYPE_EN:
+ return EuropeanNumber;
+ case PANGO_BIDI_TYPE_AN:
+ return ArabicNumber;
+ case PANGO_BIDI_TYPE_ES:
+ return EuropeanNumberSeparator;
+ case PANGO_BIDI_TYPE_ET:
+ return EuropeanNumberTerminator;
+ case PANGO_BIDI_TYPE_CS:
+ return CommonNumberSeparator;
+ case PANGO_BIDI_TYPE_NSM:
+ return NonSpacingMark;
+ case PANGO_BIDI_TYPE_BN:
+ return BoundaryNeutral;
+ case PANGO_BIDI_TYPE_B:
+ return BlockSeparator;
+ case PANGO_BIDI_TYPE_S:
+ return SegmentSeparator;
+ case PANGO_BIDI_TYPE_WS:
+ return WhiteSpaceNeutral;
+ default:
+ return OtherNeutral;
+ }
+}
+
+int umemcasecmp(const UChar* a, const UChar* b, int len)
+{
+ GOwnPtr<char> utf8a;
+ GOwnPtr<char> utf8b;
+
+ utf8a.set(g_utf16_to_utf8(a, len, 0, 0, 0));
+ utf8b.set(g_utf16_to_utf8(b, len, 0, 0, 0));
+
+ GOwnPtr<char> foldedA;
+ GOwnPtr<char> foldedB;
+
+ foldedA.set(g_utf8_casefold(utf8a.get(), -1));
+ foldedB.set(g_utf8_casefold(utf8b.get(), -1));
+
+ // FIXME: umemcasecmp needs to mimic u_memcasecmp of icu
+ // from the ICU docs:
+ // "Compare two strings case-insensitively using full case folding.
+ // his is equivalent to u_strcmp(u_strFoldCase(s1, n, options), u_strFoldCase(s2, n, options))."
+ //
+ // So it looks like we don't need the full g_utf8_collate here,
+ // but really a bitwise comparison of casefolded unicode chars (not utf-8 bytes).
+ // As there is no direct equivalent to this icu function in GLib, for now
+ // we'll use g_utf8_collate():
+
+ return g_utf8_collate(foldedA.get(), foldedB.get());
+}
+
+}
+}
diff --git a/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h b/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h
new file mode 100644
index 000000000..7bff934ba
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h
@@ -0,0 +1,244 @@
+/*
+ * 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) 2008 Jürg Billeter <j@bitron.ch>
+ * Copyright (C) 2008 Dominik Röttsches <dominik.roettsches@access-company.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 UnicodeGLib_h
+#define UnicodeGLib_h
+
+#include "GOwnPtr.h"
+#include "ScriptCodesFromICU.h"
+#include "UnicodeMacrosFromICU.h"
+
+#include <glib.h>
+#include <pango/pango.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef uint16_t UChar;
+typedef int32_t UChar32;
+
+namespace WTF {
+namespace Unicode {
+
+enum Direction {
+ LeftToRight,
+ RightToLeft,
+ EuropeanNumber,
+ EuropeanNumberSeparator,
+ EuropeanNumberTerminator,
+ ArabicNumber,
+ CommonNumberSeparator,
+ BlockSeparator,
+ SegmentSeparator,
+ WhiteSpaceNeutral,
+ OtherNeutral,
+ LeftToRightEmbedding,
+ LeftToRightOverride,
+ RightToLeftArabic,
+ RightToLeftEmbedding,
+ RightToLeftOverride,
+ PopDirectionalFormat,
+ NonSpacingMark,
+ BoundaryNeutral
+};
+
+enum DecompositionType {
+ DecompositionNone,
+ DecompositionCanonical,
+ DecompositionCompat,
+ DecompositionCircle,
+ DecompositionFinal,
+ DecompositionFont,
+ DecompositionFraction,
+ DecompositionInitial,
+ DecompositionIsolated,
+ DecompositionMedial,
+ DecompositionNarrow,
+ DecompositionNoBreak,
+ DecompositionSmall,
+ DecompositionSquare,
+ DecompositionSub,
+ DecompositionSuper,
+ DecompositionVertical,
+ DecompositionWide,
+};
+
+enum CharCategory {
+ NoCategory = 0,
+ Other_NotAssigned = U_MASK(G_UNICODE_UNASSIGNED),
+ Letter_Uppercase = U_MASK(G_UNICODE_UPPERCASE_LETTER),
+ Letter_Lowercase = U_MASK(G_UNICODE_LOWERCASE_LETTER),
+ Letter_Titlecase = U_MASK(G_UNICODE_TITLECASE_LETTER),
+ Letter_Modifier = U_MASK(G_UNICODE_MODIFIER_LETTER),
+ Letter_Other = U_MASK(G_UNICODE_OTHER_LETTER),
+
+ Mark_NonSpacing = U_MASK(G_UNICODE_NON_SPACING_MARK),
+ Mark_Enclosing = U_MASK(G_UNICODE_ENCLOSING_MARK),
+ Mark_SpacingCombining = U_MASK(G_UNICODE_COMBINING_MARK),
+
+ Number_DecimalDigit = U_MASK(G_UNICODE_DECIMAL_NUMBER),
+ Number_Letter = U_MASK(G_UNICODE_LETTER_NUMBER),
+ Number_Other = U_MASK(G_UNICODE_OTHER_NUMBER),
+
+ Separator_Space = U_MASK(G_UNICODE_SPACE_SEPARATOR),
+ Separator_Line = U_MASK(G_UNICODE_LINE_SEPARATOR),
+ Separator_Paragraph = U_MASK(G_UNICODE_PARAGRAPH_SEPARATOR),
+
+ Other_Control = U_MASK(G_UNICODE_CONTROL),
+ Other_Format = U_MASK(G_UNICODE_FORMAT),
+ Other_PrivateUse = U_MASK(G_UNICODE_PRIVATE_USE),
+ Other_Surrogate = U_MASK(G_UNICODE_SURROGATE),
+
+ Punctuation_Dash = U_MASK(G_UNICODE_DASH_PUNCTUATION),
+ Punctuation_Open = U_MASK(G_UNICODE_OPEN_PUNCTUATION),
+ Punctuation_Close = U_MASK(G_UNICODE_CLOSE_PUNCTUATION),
+ Punctuation_Connector = U_MASK(G_UNICODE_CONNECT_PUNCTUATION),
+ Punctuation_Other = U_MASK(G_UNICODE_OTHER_PUNCTUATION),
+
+ Symbol_Math = U_MASK(G_UNICODE_MATH_SYMBOL),
+ Symbol_Currency = U_MASK(G_UNICODE_CURRENCY_SYMBOL),
+ Symbol_Modifier = U_MASK(G_UNICODE_MODIFIER_SYMBOL),
+ Symbol_Other = U_MASK(G_UNICODE_OTHER_SYMBOL),
+
+ Punctuation_InitialQuote = U_MASK(G_UNICODE_INITIAL_PUNCTUATION),
+ Punctuation_FinalQuote = U_MASK(G_UNICODE_FINAL_PUNCTUATION)
+};
+
+UChar32 foldCase(UChar32);
+
+int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
+
+int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
+
+inline UChar32 toLower(UChar32 c)
+{
+ return g_unichar_tolower(c);
+}
+
+inline UChar32 toUpper(UChar32 c)
+{
+ return g_unichar_toupper(c);
+}
+
+int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
+
+inline UChar32 toTitleCase(UChar32 c)
+{
+ return g_unichar_totitle(c);
+}
+
+inline bool isArabicChar(UChar32 c)
+{
+ return c >= 0x0600 && c <= 0x06FF;
+}
+
+inline bool isAlphanumeric(UChar32 c)
+{
+ return g_unichar_isalnum(c);
+}
+
+inline bool isFormatChar(UChar32 c)
+{
+ return g_unichar_type(c) == G_UNICODE_FORMAT;
+}
+
+inline bool isSeparatorSpace(UChar32 c)
+{
+ return g_unichar_type(c) == G_UNICODE_SPACE_SEPARATOR;
+}
+
+inline bool isPrintableChar(UChar32 c)
+{
+ return g_unichar_isprint(c);
+}
+
+inline bool isDigit(UChar32 c)
+{
+ return g_unichar_isdigit(c);
+}
+
+inline bool isPunct(UChar32 c)
+{
+ return g_unichar_ispunct(c);
+}
+
+inline bool hasLineBreakingPropertyComplexContext(UChar32 c)
+{
+ // FIXME
+ return false;
+}
+
+inline bool hasLineBreakingPropertyComplexContextOrIdeographic(UChar32 c)
+{
+ // FIXME
+ return false;
+}
+
+inline UChar32 mirroredChar(UChar32 c)
+{
+ gunichar mirror = 0;
+ g_unichar_get_mirror_char(c, &mirror);
+ return mirror;
+}
+
+inline CharCategory category(UChar32 c)
+{
+ if (c > 0xffff)
+ return NoCategory;
+
+ return (CharCategory) U_MASK(g_unichar_type(c));
+}
+
+Direction direction(UChar32);
+
+inline bool isLower(UChar32 c)
+{
+ return g_unichar_islower(c);
+}
+
+inline int digitValue(UChar32 c)
+{
+ return g_unichar_digit_value(c);
+}
+
+inline uint8_t combiningClass(UChar32 c)
+{
+ // FIXME
+ // return g_unichar_combining_class(c);
+ return 0;
+}
+
+inline DecompositionType decompositionType(UChar32 c)
+{
+ // FIXME
+ return DecompositionNone;
+}
+
+int umemcasecmp(const UChar*, const UChar*, int len);
+
+}
+}
+
+#endif
+
diff --git a/Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp b/Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp
new file mode 100644
index 000000000..348693f4d
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "Collator.h"
+
+#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
+
+#include "Assertions.h"
+#include "Threading.h"
+#include <unicode/ucol.h>
+#include <string.h>
+
+#if OS(DARWIN)
+#include "RetainPtr.h"
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace WTF {
+
+static UCollator* cachedCollator;
+static Mutex& cachedCollatorMutex()
+{
+ AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
+ return mutex;
+}
+
+Collator::Collator(const char* locale)
+ : m_collator(0)
+ , m_locale(locale ? strdup(locale) : 0)
+ , m_lowerFirst(false)
+{
+}
+
+PassOwnPtr<Collator> Collator::userDefault()
+{
+#if OS(DARWIN) && USE(CF)
+ // Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work.
+#if !defined(BUILDING_ON_LEOPARD) && !OS(IOS)
+ RetainPtr<CFLocaleRef> currentLocale(AdoptCF, CFLocaleCopyCurrent());
+ CFStringRef collationOrder = (CFStringRef)CFLocaleGetValue(currentLocale.get(), kCFLocaleCollatorIdentifier);
+#else
+ RetainPtr<CFStringRef> collationOrderRetainer(AdoptCF, (CFStringRef)CFPreferencesCopyValue(CFSTR("AppleCollationOrder"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
+ CFStringRef collationOrder = collationOrderRetainer.get();
+#endif
+ char buf[256];
+ if (!collationOrder)
+ return adoptPtr(new Collator(""));
+ CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII);
+ return adoptPtr(new Collator(buf));
+#else
+ return adoptPtr(new Collator(0));
+#endif
+}
+
+Collator::~Collator()
+{
+ releaseCollator();
+ free(m_locale);
+}
+
+void Collator::setOrderLowerFirst(bool lowerFirst)
+{
+ m_lowerFirst = lowerFirst;
+}
+
+Collator::Result Collator::collate(const UChar* lhs, size_t lhsLength, const UChar* rhs, size_t rhsLength) const
+{
+ if (!m_collator)
+ createCollator();
+
+ return static_cast<Result>(ucol_strcoll(m_collator, lhs, lhsLength, rhs, rhsLength));
+}
+
+void Collator::createCollator() const
+{
+ ASSERT(!m_collator);
+ UErrorCode status = U_ZERO_ERROR;
+
+ {
+ Locker<Mutex> lock(cachedCollatorMutex());
+ if (cachedCollator) {
+ const char* cachedCollatorLocale = ucol_getLocaleByType(cachedCollator, ULOC_REQUESTED_LOCALE, &status);
+ ASSERT(U_SUCCESS(status));
+ ASSERT(cachedCollatorLocale);
+
+ UColAttributeValue cachedCollatorLowerFirst = ucol_getAttribute(cachedCollator, UCOL_CASE_FIRST, &status);
+ ASSERT(U_SUCCESS(status));
+
+ // FIXME: default locale is never matched, because ucol_getLocaleByType returns the actual one used, not 0.
+ if (m_locale && 0 == strcmp(cachedCollatorLocale, m_locale)
+ && ((UCOL_LOWER_FIRST == cachedCollatorLowerFirst && m_lowerFirst) || (UCOL_UPPER_FIRST == cachedCollatorLowerFirst && !m_lowerFirst))) {
+ m_collator = cachedCollator;
+ cachedCollator = 0;
+ return;
+ }
+ }
+ }
+
+ m_collator = ucol_open(m_locale, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ m_collator = ucol_open("", &status); // Fallback to Unicode Collation Algorithm.
+ }
+ ASSERT(U_SUCCESS(status));
+
+ ucol_setAttribute(m_collator, UCOL_CASE_FIRST, m_lowerFirst ? UCOL_LOWER_FIRST : UCOL_UPPER_FIRST, &status);
+ ASSERT(U_SUCCESS(status));
+}
+
+void Collator::releaseCollator()
+{
+ {
+ Locker<Mutex> lock(cachedCollatorMutex());
+ if (cachedCollator)
+ ucol_close(cachedCollator);
+ cachedCollator = m_collator;
+ m_collator = 0;
+ }
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h b/Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h
new file mode 100644
index 000000000..fe524b2a2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2006, 2007, 2008, 2009 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_UNICODE_ICU_H
+#define WTF_UNICODE_ICU_H
+
+#include <stdlib.h>
+#include <unicode/uchar.h>
+#include <unicode/uscript.h>
+#include <unicode/ustring.h>
+#include <unicode/utf16.h>
+
+namespace WTF {
+namespace Unicode {
+
+enum Direction {
+ LeftToRight = U_LEFT_TO_RIGHT,
+ RightToLeft = U_RIGHT_TO_LEFT,
+ EuropeanNumber = U_EUROPEAN_NUMBER,
+ EuropeanNumberSeparator = U_EUROPEAN_NUMBER_SEPARATOR,
+ EuropeanNumberTerminator = U_EUROPEAN_NUMBER_TERMINATOR,
+ ArabicNumber = U_ARABIC_NUMBER,
+ CommonNumberSeparator = U_COMMON_NUMBER_SEPARATOR,
+ BlockSeparator = U_BLOCK_SEPARATOR,
+ SegmentSeparator = U_SEGMENT_SEPARATOR,
+ WhiteSpaceNeutral = U_WHITE_SPACE_NEUTRAL,
+ OtherNeutral = U_OTHER_NEUTRAL,
+ LeftToRightEmbedding = U_LEFT_TO_RIGHT_EMBEDDING,
+ LeftToRightOverride = U_LEFT_TO_RIGHT_OVERRIDE,
+ RightToLeftArabic = U_RIGHT_TO_LEFT_ARABIC,
+ RightToLeftEmbedding = U_RIGHT_TO_LEFT_EMBEDDING,
+ RightToLeftOverride = U_RIGHT_TO_LEFT_OVERRIDE,
+ PopDirectionalFormat = U_POP_DIRECTIONAL_FORMAT,
+ NonSpacingMark = U_DIR_NON_SPACING_MARK,
+ BoundaryNeutral = U_BOUNDARY_NEUTRAL
+};
+
+enum DecompositionType {
+ DecompositionNone = U_DT_NONE,
+ DecompositionCanonical = U_DT_CANONICAL,
+ DecompositionCompat = U_DT_COMPAT,
+ DecompositionCircle = U_DT_CIRCLE,
+ DecompositionFinal = U_DT_FINAL,
+ DecompositionFont = U_DT_FONT,
+ DecompositionFraction = U_DT_FRACTION,
+ DecompositionInitial = U_DT_INITIAL,
+ DecompositionIsolated = U_DT_ISOLATED,
+ DecompositionMedial = U_DT_MEDIAL,
+ DecompositionNarrow = U_DT_NARROW,
+ DecompositionNoBreak = U_DT_NOBREAK,
+ DecompositionSmall = U_DT_SMALL,
+ DecompositionSquare = U_DT_SQUARE,
+ DecompositionSub = U_DT_SUB,
+ DecompositionSuper = U_DT_SUPER,
+ DecompositionVertical = U_DT_VERTICAL,
+ DecompositionWide = U_DT_WIDE,
+};
+
+enum CharCategory {
+ NoCategory = 0,
+ Other_NotAssigned = U_MASK(U_GENERAL_OTHER_TYPES),
+ Letter_Uppercase = U_MASK(U_UPPERCASE_LETTER),
+ Letter_Lowercase = U_MASK(U_LOWERCASE_LETTER),
+ Letter_Titlecase = U_MASK(U_TITLECASE_LETTER),
+ Letter_Modifier = U_MASK(U_MODIFIER_LETTER),
+ Letter_Other = U_MASK(U_OTHER_LETTER),
+
+ Mark_NonSpacing = U_MASK(U_NON_SPACING_MARK),
+ Mark_Enclosing = U_MASK(U_ENCLOSING_MARK),
+ Mark_SpacingCombining = U_MASK(U_COMBINING_SPACING_MARK),
+
+ Number_DecimalDigit = U_MASK(U_DECIMAL_DIGIT_NUMBER),
+ Number_Letter = U_MASK(U_LETTER_NUMBER),
+ Number_Other = U_MASK(U_OTHER_NUMBER),
+
+ Separator_Space = U_MASK(U_SPACE_SEPARATOR),
+ Separator_Line = U_MASK(U_LINE_SEPARATOR),
+ Separator_Paragraph = U_MASK(U_PARAGRAPH_SEPARATOR),
+
+ Other_Control = U_MASK(U_CONTROL_CHAR),
+ Other_Format = U_MASK(U_FORMAT_CHAR),
+ Other_PrivateUse = U_MASK(U_PRIVATE_USE_CHAR),
+ Other_Surrogate = U_MASK(U_SURROGATE),
+
+ Punctuation_Dash = U_MASK(U_DASH_PUNCTUATION),
+ Punctuation_Open = U_MASK(U_START_PUNCTUATION),
+ Punctuation_Close = U_MASK(U_END_PUNCTUATION),
+ Punctuation_Connector = U_MASK(U_CONNECTOR_PUNCTUATION),
+ Punctuation_Other = U_MASK(U_OTHER_PUNCTUATION),
+
+ Symbol_Math = U_MASK(U_MATH_SYMBOL),
+ Symbol_Currency = U_MASK(U_CURRENCY_SYMBOL),
+ Symbol_Modifier = U_MASK(U_MODIFIER_SYMBOL),
+ Symbol_Other = U_MASK(U_OTHER_SYMBOL),
+
+ Punctuation_InitialQuote = U_MASK(U_INITIAL_PUNCTUATION),
+ Punctuation_FinalQuote = U_MASK(U_FINAL_PUNCTUATION)
+};
+
+inline UChar32 foldCase(UChar32 c)
+{
+ return u_foldCase(c, U_FOLD_CASE_DEFAULT);
+}
+
+inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int realLength = u_strFoldCase(result, resultLength, src, srcLength, U_FOLD_CASE_DEFAULT, &status);
+ *error = !U_SUCCESS(status);
+ return realLength;
+}
+
+inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int realLength = u_strToLower(result, resultLength, src, srcLength, "", &status);
+ *error = !!U_FAILURE(status);
+ return realLength;
+}
+
+inline UChar32 toLower(UChar32 c)
+{
+ return u_tolower(c);
+}
+
+inline UChar32 toUpper(UChar32 c)
+{
+ return u_toupper(c);
+}
+
+inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int realLength = u_strToUpper(result, resultLength, src, srcLength, "", &status);
+ *error = !!U_FAILURE(status);
+ return realLength;
+}
+
+inline UChar32 toTitleCase(UChar32 c)
+{
+ return u_totitle(c);
+}
+
+inline bool isArabicChar(UChar32 c)
+{
+ return ublock_getCode(c) == UBLOCK_ARABIC;
+}
+
+inline bool isAlphanumeric(UChar32 c)
+{
+ return u_isalnum(c);
+}
+
+inline bool isSeparatorSpace(UChar32 c)
+{
+ return u_charType(c) == U_SPACE_SEPARATOR;
+}
+
+inline bool isPrintableChar(UChar32 c)
+{
+ return !!u_isprint(c);
+}
+
+inline bool isPunct(UChar32 c)
+{
+ return !!u_ispunct(c);
+}
+
+inline bool hasLineBreakingPropertyComplexContext(UChar32 c)
+{
+ return u_getIntPropertyValue(c, UCHAR_LINE_BREAK) == U_LB_COMPLEX_CONTEXT;
+}
+
+inline bool hasLineBreakingPropertyComplexContextOrIdeographic(UChar32 c)
+{
+ int32_t prop = u_getIntPropertyValue(c, UCHAR_LINE_BREAK);
+ return prop == U_LB_COMPLEX_CONTEXT || prop == U_LB_IDEOGRAPHIC;
+}
+
+inline UChar32 mirroredChar(UChar32 c)
+{
+ return u_charMirror(c);
+}
+
+inline CharCategory category(UChar32 c)
+{
+ return static_cast<CharCategory>(U_GET_GC_MASK(c));
+}
+
+inline Direction direction(UChar32 c)
+{
+ return static_cast<Direction>(u_charDirection(c));
+}
+
+inline bool isLower(UChar32 c)
+{
+ return !!u_islower(c);
+}
+
+inline uint8_t combiningClass(UChar32 c)
+{
+ return u_getCombiningClass(c);
+}
+
+inline DecompositionType decompositionType(UChar32 c)
+{
+ return static_cast<DecompositionType>(u_getIntPropertyValue(c, UCHAR_DECOMPOSITION_TYPE));
+}
+
+inline int umemcasecmp(const UChar* a, const UChar* b, int len)
+{
+ return u_memcasecmp(a, b, len, U_FOLD_CASE_DEFAULT);
+}
+
+} }
+
+#endif // WTF_UNICODE_ICU_H
diff --git a/Source/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/Source/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h
new file mode 100644
index 000000000..e4f39b292
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2006, 2007, 2008, 2009 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_UNICODE_QT4_H
+#define WTF_UNICODE_QT4_H
+
+#include "ScriptCodesFromICU.h"
+#include "UnicodeMacrosFromICU.h"
+
+#include <QChar>
+#include <QString>
+
+#include <config.h>
+
+#include <stdint.h>
+#if USE(ICU_UNICODE)
+#include <unicode/ubrk.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+namespace QUnicodeTables {
+ struct Properties {
+ ushort category : 8;
+ ushort line_break_class : 8;
+ ushort direction : 8;
+ ushort combiningClass :8;
+ ushort joining : 2;
+ signed short digitValue : 6; /* 5 needed */
+ ushort unicodeVersion : 4;
+ ushort lowerCaseSpecial : 1;
+ ushort upperCaseSpecial : 1;
+ ushort titleCaseSpecial : 1;
+ ushort caseFoldSpecial : 1; /* currently unused */
+ signed short mirrorDiff : 16;
+ signed short lowerCaseDiff : 16;
+ signed short upperCaseDiff : 16;
+ signed short titleCaseDiff : 16;
+ signed short caseFoldDiff : 16;
+ };
+ Q_CORE_EXPORT const Properties * QT_FASTCALL properties(uint ucs4);
+ Q_CORE_EXPORT const Properties * QT_FASTCALL properties(ushort ucs2);
+}
+QT_END_NAMESPACE
+
+// ugly hack to make UChar compatible with JSChar in API/JSStringRef.h
+#if defined(Q_OS_WIN) || (COMPILER(RVCT) && !OS(LINUX))
+typedef wchar_t UChar;
+#else
+typedef uint16_t UChar;
+#endif
+
+#if !USE(ICU_UNICODE)
+typedef uint32_t UChar32;
+#endif
+
+namespace WTF {
+namespace Unicode {
+
+enum Direction {
+ LeftToRight = QChar::DirL,
+ RightToLeft = QChar::DirR,
+ EuropeanNumber = QChar::DirEN,
+ EuropeanNumberSeparator = QChar::DirES,
+ EuropeanNumberTerminator = QChar::DirET,
+ ArabicNumber = QChar::DirAN,
+ CommonNumberSeparator = QChar::DirCS,
+ BlockSeparator = QChar::DirB,
+ SegmentSeparator = QChar::DirS,
+ WhiteSpaceNeutral = QChar::DirWS,
+ OtherNeutral = QChar::DirON,
+ LeftToRightEmbedding = QChar::DirLRE,
+ LeftToRightOverride = QChar::DirLRO,
+ RightToLeftArabic = QChar::DirAL,
+ RightToLeftEmbedding = QChar::DirRLE,
+ RightToLeftOverride = QChar::DirRLO,
+ PopDirectionalFormat = QChar::DirPDF,
+ NonSpacingMark = QChar::DirNSM,
+ BoundaryNeutral = QChar::DirBN
+};
+
+enum DecompositionType {
+ DecompositionNone = QChar::NoDecomposition,
+ DecompositionCanonical = QChar::Canonical,
+ DecompositionCompat = QChar::Compat,
+ DecompositionCircle = QChar::Circle,
+ DecompositionFinal = QChar::Final,
+ DecompositionFont = QChar::Font,
+ DecompositionFraction = QChar::Fraction,
+ DecompositionInitial = QChar::Initial,
+ DecompositionIsolated = QChar::Isolated,
+ DecompositionMedial = QChar::Medial,
+ DecompositionNarrow = QChar::Narrow,
+ DecompositionNoBreak = QChar::NoBreak,
+ DecompositionSmall = QChar::Small,
+ DecompositionSquare = QChar::Square,
+ DecompositionSub = QChar::Sub,
+ DecompositionSuper = QChar::Super,
+ DecompositionVertical = QChar::Vertical,
+ DecompositionWide = QChar::Wide
+};
+
+enum CharCategory {
+ NoCategory = 0,
+ Mark_NonSpacing = U_MASK(QChar::Mark_NonSpacing),
+ Mark_SpacingCombining = U_MASK(QChar::Mark_SpacingCombining),
+ Mark_Enclosing = U_MASK(QChar::Mark_Enclosing),
+ Number_DecimalDigit = U_MASK(QChar::Number_DecimalDigit),
+ Number_Letter = U_MASK(QChar::Number_Letter),
+ Number_Other = U_MASK(QChar::Number_Other),
+ Separator_Space = U_MASK(QChar::Separator_Space),
+ Separator_Line = U_MASK(QChar::Separator_Line),
+ Separator_Paragraph = U_MASK(QChar::Separator_Paragraph),
+ Other_Control = U_MASK(QChar::Other_Control),
+ Other_Format = U_MASK(QChar::Other_Format),
+ Other_Surrogate = U_MASK(QChar::Other_Surrogate),
+ Other_PrivateUse = U_MASK(QChar::Other_PrivateUse),
+ Other_NotAssigned = U_MASK(QChar::Other_NotAssigned),
+ Letter_Uppercase = U_MASK(QChar::Letter_Uppercase),
+ Letter_Lowercase = U_MASK(QChar::Letter_Lowercase),
+ Letter_Titlecase = U_MASK(QChar::Letter_Titlecase),
+ Letter_Modifier = U_MASK(QChar::Letter_Modifier),
+ Letter_Other = U_MASK(QChar::Letter_Other),
+ Punctuation_Connector = U_MASK(QChar::Punctuation_Connector),
+ Punctuation_Dash = U_MASK(QChar::Punctuation_Dash),
+ Punctuation_Open = U_MASK(QChar::Punctuation_Open),
+ Punctuation_Close = U_MASK(QChar::Punctuation_Close),
+ Punctuation_InitialQuote = U_MASK(QChar::Punctuation_InitialQuote),
+ Punctuation_FinalQuote = U_MASK(QChar::Punctuation_FinalQuote),
+ Punctuation_Other = U_MASK(QChar::Punctuation_Other),
+ Symbol_Math = U_MASK(QChar::Symbol_Math),
+ Symbol_Currency = U_MASK(QChar::Symbol_Currency),
+ Symbol_Modifier = U_MASK(QChar::Symbol_Modifier),
+ Symbol_Other = U_MASK(QChar::Symbol_Other)
+};
+
+
+// FIXME: handle surrogates correctly in all methods
+
+inline UChar32 toLower(UChar32 ch)
+{
+ return QChar::toLower(uint32_t(ch));
+}
+
+inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ const UChar *e = src + srcLength;
+ const UChar *s = src;
+ UChar *r = result;
+ uint rindex = 0;
+
+ // this avoids one out of bounds check in the loop
+ if (s < e && QChar(*s).isLowSurrogate()) {
+ if (r)
+ r[rindex] = *s++;
+ ++rindex;
+ }
+
+ int needed = 0;
+ while (s < e && (rindex < uint(resultLength) || !r)) {
+ uint c = *s;
+ if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
+ c = QChar::surrogateToUcs4(*(s - 1), c);
+ const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
+ if (prop->lowerCaseSpecial) {
+ QString qstring;
+ if (c < 0x10000) {
+ qstring += QChar(c);
+ } else {
+ qstring += QChar(*(s-1));
+ qstring += QChar(*s);
+ }
+ qstring = qstring.toLower();
+ for (int i = 0; i < qstring.length(); ++i) {
+ if (rindex >= uint(resultLength)) {
+ needed += qstring.length() - i;
+ break;
+ }
+ if (r)
+ r[rindex] = qstring.at(i).unicode();
+ ++rindex;
+ }
+ } else {
+ if (r)
+ r[rindex] = *s + prop->lowerCaseDiff;
+ ++rindex;
+ }
+ ++s;
+ }
+ if (s < e)
+ needed += e - s;
+ *error = (needed != 0);
+ if (rindex < uint(resultLength))
+ r[rindex] = 0;
+ return rindex + needed;
+}
+
+inline UChar32 toUpper(UChar32 c)
+{
+ return QChar::toUpper(uint32_t(c));
+}
+
+inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ const UChar *e = src + srcLength;
+ const UChar *s = src;
+ UChar *r = result;
+ int rindex = 0;
+
+ // this avoids one out of bounds check in the loop
+ if (s < e && QChar(*s).isLowSurrogate()) {
+ if (r)
+ r[rindex] = *s++;
+ ++rindex;
+ }
+
+ int needed = 0;
+ while (s < e && (rindex < resultLength || !r)) {
+ uint c = *s;
+ if (QChar(c).isLowSurrogate() && QChar(*(s - 1)).isHighSurrogate())
+ c = QChar::surrogateToUcs4(*(s - 1), c);
+ const QUnicodeTables::Properties *prop = QUnicodeTables::properties(c);
+ if (prop->upperCaseSpecial) {
+ QString qstring;
+ if (c < 0x10000) {
+ qstring += QChar(c);
+ } else {
+ qstring += QChar(*(s-1));
+ qstring += QChar(*s);
+ }
+ qstring = qstring.toUpper();
+ for (int i = 0; i < qstring.length(); ++i) {
+ if (rindex >= resultLength) {
+ needed += qstring.length() - i;
+ break;
+ }
+ if (r)
+ r[rindex] = qstring.at(i).unicode();
+ ++rindex;
+ }
+ } else {
+ if (r)
+ r[rindex] = *s + prop->upperCaseDiff;
+ ++rindex;
+ }
+ ++s;
+ }
+ if (s < e)
+ needed += e - s;
+ *error = (needed != 0);
+ if (rindex < resultLength)
+ r[rindex] = 0;
+ return rindex + needed;
+}
+
+inline int toTitleCase(UChar32 c)
+{
+ return QChar::toTitleCase(uint32_t(c));
+}
+
+inline UChar32 foldCase(UChar32 c)
+{
+ return QChar::toCaseFolded(uint32_t(c));
+}
+
+inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ // FIXME: handle special casing. Easiest with some low level API in Qt
+ *error = false;
+ if (resultLength < srcLength) {
+ *error = true;
+ return srcLength;
+ }
+ for (int i = 0; i < srcLength; ++i)
+ result[i] = QChar::toCaseFolded(ushort(src[i]));
+ return srcLength;
+}
+
+inline bool isArabicChar(UChar32 c)
+{
+ return c >= 0x0600 && c <= 0x06FF;
+}
+
+inline bool isPrintableChar(UChar32 c)
+{
+ const uint test = U_MASK(QChar::Other_Control) |
+ U_MASK(QChar::Other_NotAssigned);
+ return !(U_MASK(QChar::category(uint32_t(c))) & test);
+}
+
+inline bool isSeparatorSpace(UChar32 c)
+{
+ return QChar::category(uint32_t(c)) == QChar::Separator_Space;
+}
+
+inline bool isPunct(UChar32 c)
+{
+ const uint test = U_MASK(QChar::Punctuation_Connector) |
+ U_MASK(QChar::Punctuation_Dash) |
+ U_MASK(QChar::Punctuation_Open) |
+ U_MASK(QChar::Punctuation_Close) |
+ U_MASK(QChar::Punctuation_InitialQuote) |
+ U_MASK(QChar::Punctuation_FinalQuote) |
+ U_MASK(QChar::Punctuation_Other);
+ return U_MASK(QChar::category(uint32_t(c))) & test;
+}
+
+inline bool isLower(UChar32 c)
+{
+ return QChar::category(uint32_t(c)) == QChar::Letter_Lowercase;
+}
+
+inline bool hasLineBreakingPropertyComplexContext(UChar32)
+{
+ // FIXME: Implement this to return whether the character has line breaking property SA (Complex Context).
+ return false;
+}
+
+inline UChar32 mirroredChar(UChar32 c)
+{
+ return QChar::mirroredChar(uint32_t(c));
+}
+
+inline uint8_t combiningClass(UChar32 c)
+{
+ return QChar::combiningClass(uint32_t(c));
+}
+
+inline DecompositionType decompositionType(UChar32 c)
+{
+ return (DecompositionType)QChar::decompositionTag(c);
+}
+
+inline int umemcasecmp(const UChar* a, const UChar* b, int len)
+{
+ // handle surrogates correctly
+ for (int i = 0; i < len; ++i) {
+ uint c1 = QChar::toCaseFolded(ushort(a[i]));
+ uint c2 = QChar::toCaseFolded(ushort(b[i]));
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ return 0;
+}
+
+inline Direction direction(UChar32 c)
+{
+ return (Direction)QChar::direction(uint32_t(c));
+}
+
+inline CharCategory category(UChar32 c)
+{
+ return (CharCategory) U_MASK(QChar::category(uint32_t(c)));
+}
+
+} // namespace Unicode
+} // namespace WTF
+
+#endif // WTF_UNICODE_QT4_H
diff --git a/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.cpp b/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.cpp
new file mode 100644
index 000000000..96dac7d40
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.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.
+ *
+ * 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 "UnicodeWinCE.h"
+
+#include <wchar.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 isSpace(UChar c)
+{
+ return !!iswspace(c);
+}
+
+bool isLetter(UChar c)
+{
+ return !!iswalpha(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;
+
+ int remainingCharacters = 0;
+ if (sourceLength <= resultLength)
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+ else
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+
+ if (sourceIterator < sourceEnd)
+ remainingCharacters += sourceEnd - sourceIterator;
+ *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;
+
+ int remainingCharacters = 0;
+ if (sourceLength <= resultLength)
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+ else
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+
+ if (sourceIterator < sourceEnd)
+ remainingCharacters += sourceEnd - sourceIterator;
+ *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>(UnicodeCE::direction(c));
+}
+
+CharCategory category(unsigned int c)
+{
+ return static_cast<CharCategory>(TO_MASK((__int8) UnicodeCE::category(c)));
+}
+
+DecompositionType decompositionType(UChar32 c)
+{
+ return static_cast<DecompositionType>(UnicodeCE::decompositionType(c));
+}
+
+unsigned char combiningClass(UChar32 c)
+{
+ return UnicodeCE::combiningClass(c);
+}
+
+UChar mirroredChar(UChar32 c)
+{
+ return UnicodeCE::mirroredChar(c);
+}
+
+int digitValue(UChar c)
+{
+ return UnicodeCE::digitValue(c);
+}
+
+} // namespace Unicode
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h b/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h
new file mode 100644
index 000000000..af6ff0748
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/unicode/wince/UnicodeWinCE.h
@@ -0,0 +1,178 @@
+/*
+ * 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 "ScriptCodesFromICU.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/Source/JavaScriptCore/wtf/win/MainThreadWin.cpp b/Source/JavaScriptCore/wtf/win/MainThreadWin.cpp
new file mode 100644
index 000000000..ee3a27377
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/win/MainThreadWin.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile 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.
+ */
+
+#include "config.h"
+#include "MainThread.h"
+
+#include "Assertions.h"
+#include "Threading.h"
+#if !OS(WINCE)
+#include <windows.h>
+#endif
+
+namespace WTF {
+
+static HWND threadingWindowHandle;
+static UINT threadingFiredMessage;
+const LPCWSTR kThreadingWindowClassName = L"ThreadingWindowClass";
+
+LRESULT CALLBACK ThreadingWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == threadingFiredMessage)
+ dispatchFunctionsFromMainThread();
+ else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+void initializeMainThreadPlatform()
+{
+ if (threadingWindowHandle)
+ return;
+
+ HWND hWndParent = 0;
+#if OS(WINCE)
+ WNDCLASS wcex;
+ memset(&wcex, 0, sizeof(WNDCLASS));
+#else
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+#endif
+ wcex.lpfnWndProc = ThreadingWindowWndProc;
+ wcex.lpszClassName = kThreadingWindowClassName;
+#if OS(WINCE)
+ RegisterClass(&wcex);
+#else
+ RegisterClassEx(&wcex);
+ hWndParent = HWND_MESSAGE;
+#endif
+
+ 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()
+{
+ ASSERT(threadingWindowHandle);
+ PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0);
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/win/OwnPtrWin.cpp b/Source/JavaScriptCore/wtf/win/OwnPtrWin.cpp
new file mode 100644
index 000000000..67a32ff77
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/win/OwnPtrWin.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile, 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.
+ *
+ * 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 "OwnPtr.h"
+
+#include <windows.h>
+
+namespace WTF {
+
+void deleteOwnedPtr(HBITMAP ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+void deleteOwnedPtr(HBRUSH ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+void deleteOwnedPtr(HDC ptr)
+{
+ if (ptr)
+ DeleteDC(ptr);
+}
+
+void deleteOwnedPtr(HFONT ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+void deleteOwnedPtr(HPALETTE ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+void deleteOwnedPtr(HPEN ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+void deleteOwnedPtr(HRGN ptr)
+{
+ if (ptr)
+ DeleteObject(ptr);
+}
+
+}
diff --git a/Source/JavaScriptCore/wtf/wince/FastMallocWinCE.h b/Source/JavaScriptCore/wtf/wince/FastMallocWinCE.h
new file mode 100644
index 000000000..d91a5f2c9
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wince/FastMallocWinCE.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, 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_FastMallocWinCE_h
+#define WTF_FastMallocWinCE_h
+
+#include <new.h>
+
+#ifdef __cplusplus
+#include <new>
+#include "MemoryManager.h"
+extern "C" {
+#endif
+
+void* fastMalloc(size_t n);
+void* fastCalloc(size_t n_elements, size_t element_size);
+void fastFree(void* p);
+void* fastRealloc(void* p, size_t n);
+void* fastZeroedMalloc(size_t n);
+// These functions return 0 if an allocation fails.
+void* tryFastMalloc(size_t n);
+void* tryFastZeroedMalloc(size_t n);
+void* tryFastCalloc(size_t n_elements, size_t element_size);
+void* tryFastRealloc(void* p, size_t n);
+char* fastStrDup(const char*);
+
+#ifndef NDEBUG
+void fastMallocForbid();
+void fastMallocAllow();
+#endif
+
+#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
+
+#define malloc(n) fastMalloc(n)
+#define calloc(n_elements, element_size) fastCalloc(n_elements, element_size)
+#define realloc(p, n) fastRealloc(p, n)
+#define free(p) fastFree(p)
+#define strdup(p) fastStrDup(p)
+
+#else
+
+#define strdup(p) _strdup(p)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
+static inline void* __cdecl operator new(size_t s) { return fastMalloc(s); }
+static inline void __cdecl operator delete(void* p) { fastFree(p); }
+static inline void* __cdecl operator new[](size_t s) { return fastMalloc(s); }
+static inline void __cdecl operator delete[](void* p) { fastFree(p); }
+static inline void* operator new(size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
+static inline void operator delete(void* p, const std::nothrow_t&) throw() { fastFree(p); }
+static inline void* operator new[](size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
+static inline void operator delete[](void* p, const std::nothrow_t&) throw() { fastFree(p); }
+#endif
+
+namespace WTF {
+ // This defines a type which holds an unsigned integer and is the same
+ // size as the minimally aligned memory allocation.
+ typedef unsigned long long AllocAlignmentInteger;
+
+ namespace Internal {
+ enum AllocType { // Start with an unusual number instead of zero, because zero is common.
+ AllocTypeMalloc = 0x375d6750, // Encompasses fastMalloc, fastZeroedMalloc, fastCalloc, fastRealloc.
+ AllocTypeClassNew, // Encompasses class operator new from FastAllocBase.
+ AllocTypeClassNewArray, // Encompasses class operator new[] from FastAllocBase.
+ AllocTypeFastNew, // Encompasses fastNew.
+ AllocTypeFastNewArray, // Encompasses fastNewArray.
+ AllocTypeNew, // Encompasses global operator new.
+ AllocTypeNewArray // Encompasses global operator new[].
+ };
+ }
+
+
+#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+
+ // Malloc validation is a scheme whereby a tag is attached to an
+ // allocation which identifies how it was originally allocated.
+ // This allows us to verify that the freeing operation matches the
+ // allocation operation. If memory is allocated with operator new[]
+ // but freed with free or delete, this system would detect that.
+ // In the implementation here, the tag is an integer prepended to
+ // the allocation memory which is assigned one of the AllocType
+ // enumeration values. An alternative implementation of this
+ // scheme could store the tag somewhere else or ignore it.
+ // Users of FastMalloc don't need to know or care how this tagging
+ // is implemented.
+
+ namespace Internal {
+
+ // Return the AllocType tag associated with the allocated block p.
+ inline AllocType fastMallocMatchValidationType(const void* p)
+ {
+ const AllocAlignmentInteger* type = static_cast<const AllocAlignmentInteger*>(p) - 1;
+ return static_cast<AllocType>(*type);
+ }
+
+ // Return the address of the AllocType tag associated with the allocated block p.
+ inline AllocAlignmentInteger* fastMallocMatchValidationValue(void* p)
+ {
+ return reinterpret_cast<AllocAlignmentInteger*>(static_cast<char*>(p) - sizeof(AllocAlignmentInteger));
+ }
+
+ // Set the AllocType tag to be associaged with the allocated block p.
+ inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
+ {
+ AllocAlignmentInteger* type = static_cast<AllocAlignmentInteger*>(p) - 1;
+ *type = static_cast<AllocAlignmentInteger>(allocType);
+ }
+
+ // Handle a detected alloc/free mismatch. By default this calls CRASH().
+ void fastMallocMatchFailed(void* p);
+
+ } // namespace Internal
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateMalloc(void* p, Internal::AllocType allocType)
+ {
+ if (!p)
+ return;
+
+ Internal::setFastMallocMatchValidationType(p, allocType);
+ }
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateFree(void* p, Internal::AllocType allocType)
+ {
+ if (!p)
+ return;
+
+ if (Internal::fastMallocMatchValidationType(p) != allocType)
+ Internal::fastMallocMatchFailed(p);
+ Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc); // Set it to this so that fastFree thinks it's OK.
+ }
+
+#else
+
+ inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
+ {
+ }
+
+ inline void fastMallocMatchValidateFree(void*, Internal::AllocType)
+ {
+ }
+
+#endif
+
+} // namespace WTF
+
+#endif
+
+#endif // WTF_FastMallocWinCE_h
diff --git a/Source/JavaScriptCore/wtf/wince/MemoryManager.cpp b/Source/JavaScriptCore/wtf/wince/MemoryManager.cpp
new file mode 100644
index 000000000..81d4f805b
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wince/MemoryManager.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008-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 "MemoryManager.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#undef strdup
+#undef _strdup
+#undef VirtualAlloc
+#undef VirtualFree
+
+#include <malloc.h>
+#include <windows.h>
+
+namespace WTF {
+
+MemoryManager* memoryManager()
+{
+ static MemoryManager mm;
+ return &mm;
+}
+
+MemoryManager::MemoryManager()
+: m_allocationCanFail(false)
+{
+}
+
+MemoryManager::~MemoryManager()
+{
+}
+
+HBITMAP MemoryManager::createCompatibleBitmap(HDC hdc, int width, int height)
+{
+ return ::CreateCompatibleBitmap(hdc, width, height);
+}
+
+HBITMAP MemoryManager::createDIBSection(const BITMAPINFO* pbmi, void** ppvBits)
+{
+ return ::CreateDIBSection(0, pbmi, DIB_RGB_COLORS, ppvBits, 0, 0);
+}
+
+void* MemoryManager::m_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+void* MemoryManager::m_calloc(size_t num, size_t size)
+{
+ return calloc(num, size);
+}
+
+void* MemoryManager::m_realloc(void* p, size_t size)
+{
+ return realloc(p, size);
+}
+
+void MemoryManager::m_free(void* p)
+{
+ return free(p);
+}
+
+bool MemoryManager::resizeMemory(void*, size_t)
+{
+ return false;
+}
+
+void* MemoryManager::allocate64kBlock()
+{
+ return VirtualAlloc(0, 65536, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+}
+
+void MemoryManager::free64kBlock(void* p)
+{
+ VirtualFree(p, 65536, MEM_RELEASE);
+}
+
+bool MemoryManager::onIdle(DWORD& timeLimitMs)
+{
+ return false;
+}
+
+LPVOID MemoryManager::virtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect)
+{
+ return ::VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
+}
+
+BOOL MemoryManager::virtualFree(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType)
+{
+ return ::VirtualFree(lpAddress, dwSize, dwFreeType);
+}
+
+
+#if defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC
+
+void *fastMalloc(size_t n) { return malloc(n); }
+void *fastCalloc(size_t n_elements, size_t element_size) { return calloc(n_elements, element_size); }
+void fastFree(void* p) { return free(p); }
+void *fastRealloc(void* p, size_t n) { return realloc(p, n); }
+
+#else
+
+void *fastMalloc(size_t n) { return MemoryManager::m_malloc(n); }
+void *fastCalloc(size_t n_elements, size_t element_size) { return MemoryManager::m_calloc(n_elements, element_size); }
+void fastFree(void* p) { return MemoryManager::m_free(p); }
+void *fastRealloc(void* p, size_t n) { return MemoryManager::m_realloc(p, n); }
+
+#endif
+
+#ifndef NDEBUG
+void fastMallocForbid() {}
+void fastMallocAllow() {}
+#endif
+
+void* fastZeroedMalloc(size_t n)
+{
+ void* p = fastMalloc(n);
+ if (p)
+ memset(p, 0, n);
+ return p;
+}
+
+TryMallocReturnValue tryFastMalloc(size_t n)
+{
+ MemoryAllocationCanFail canFail;
+ return fastMalloc(n);
+}
+
+TryMallocReturnValue tryFastZeroedMalloc(size_t n)
+{
+ MemoryAllocationCanFail canFail;
+ return fastZeroedMalloc(n);
+}
+
+TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size)
+{
+ MemoryAllocationCanFail canFail;
+ return fastCalloc(n_elements, element_size);
+}
+
+TryMallocReturnValue tryFastRealloc(void* p, size_t n)
+{
+ MemoryAllocationCanFail canFail;
+ return fastRealloc(p, n);
+}
+
+char* fastStrDup(const char* str)
+{
+ return _strdup(str);
+}
+
+} \ No newline at end of file
diff --git a/Source/JavaScriptCore/wtf/wince/MemoryManager.h b/Source/JavaScriptCore/wtf/wince/MemoryManager.h
new file mode 100644
index 000000000..f405612df
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wince/MemoryManager.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008-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.
+ */
+
+#pragma once
+
+#include <winbase.h>
+
+typedef struct HBITMAP__* HBITMAP;
+typedef struct HDC__* HDC;
+typedef void *HANDLE;
+typedef struct tagBITMAPINFO BITMAPINFO;
+
+namespace WTF {
+
+ class MemoryManager {
+ public:
+ MemoryManager();
+ ~MemoryManager();
+
+ bool allocationCanFail() const { return m_allocationCanFail; }
+ void setAllocationCanFail(bool c) { m_allocationCanFail = c; }
+
+ static HBITMAP createCompatibleBitmap(HDC hdc, int width, int height);
+ static HBITMAP createDIBSection(const BITMAPINFO* pbmi, void** ppvBits);
+ static void* m_malloc(size_t size);
+ static void* m_calloc(size_t num, size_t size);
+ static void* m_realloc(void* p, size_t size);
+ static void m_free(void*);
+ static bool resizeMemory(void* p, size_t newSize);
+ static void* allocate64kBlock();
+ static void free64kBlock(void*);
+ static bool onIdle(DWORD& timeLimitMs);
+ static LPVOID virtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect);
+ static BOOL virtualFree(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType);
+
+ private:
+ friend MemoryManager* memoryManager();
+
+ bool m_allocationCanFail;
+ };
+
+ MemoryManager* memoryManager();
+
+ class MemoryAllocationCanFail {
+ public:
+ MemoryAllocationCanFail() : m_old(memoryManager()->allocationCanFail()) { memoryManager()->setAllocationCanFail(true); }
+ ~MemoryAllocationCanFail() { memoryManager()->setAllocationCanFail(m_old); }
+ private:
+ bool m_old;
+ };
+
+ class MemoryAllocationCannotFail {
+ public:
+ MemoryAllocationCannotFail() : m_old(memoryManager()->allocationCanFail()) { memoryManager()->setAllocationCanFail(false); }
+ ~MemoryAllocationCannotFail() { memoryManager()->setAllocationCanFail(m_old); }
+ private:
+ bool m_old;
+ };
+}
+
+using WTF::MemoryManager;
+using WTF::memoryManager;
+using WTF::MemoryAllocationCanFail;
+using WTF::MemoryAllocationCannotFail;
diff --git a/Source/JavaScriptCore/wtf/wtf.pri b/Source/JavaScriptCore/wtf/wtf.pri
new file mode 100644
index 000000000..2a3c609d5
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wtf.pri
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------------
+# This file contains shared rules used both when building WTF itself
+# and for targets that depend in some way on WTF.
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+load(features)
+
+SOURCE_DIR = $${ROOT_WEBKIT_DIR}/Source/JavaScriptCore/wtf
+
+INCLUDEPATH += \
+ $$SOURCE_DIR/.. \
+ $$SOURCE_DIR \
+ $$SOURCE_DIR/gobject \
+ $$SOURCE_DIR/qt \
+ $$SOURCE_DIR/unicode
+
+VPATH += $$SOURCE_DIR
+
+contains(CONFIG, use_system_icu) {
+ DEFINES += WTF_USE_ICU_UNICODE=1
+ DEFINES -= WTF_USE_QT4_UNICODE
+ LIBS += -licuuc -licui18n
+} else {
+ DEFINES += WTF_USE_QT4_UNICODE=1
+ DEFINES -= WTF_USE_ICU_UNICODE
+}
+
+v8 {
+ !haveQt(5): error("To build QtWebKit+V8 you need to use Qt 5")
+ DEFINES *= WTF_USE_V8=1
+ INCLUDEPATH += $${ROOT_WEBKIT_DIR}/Source/WebKit/qt/v8/ForwardingHeaders
+ QT += v8-private declarative
+}
+
+linux-*:!contains(DEFINES, USE_QTMULTIMEDIA=1) {
+ !contains(QT_CONFIG, no-pkg-config):system(pkg-config --exists glib-2.0 gio-2.0 gstreamer-0.10): {
+ DEFINES += ENABLE_GLIB_SUPPORT=1
+ PKGCONFIG += glib-2.0 gio-2.0
+ }
+}
+
+win32-*: LIBS += -lwinmm
diff --git a/Source/JavaScriptCore/wtf/wtf.pro b/Source/JavaScriptCore/wtf/wtf.pro
new file mode 100644
index 000000000..e59d118e2
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wtf.pro
@@ -0,0 +1,253 @@
+# -------------------------------------------------------------------
+# Project file for WTF
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+TEMPLATE = lib
+TARGET = WTF
+
+include(wtf.pri)
+
+CONFIG += staticlib
+
+QT += core
+QT -= gui
+
+*-g++*:QMAKE_CXXFLAGS_RELEASE -= -O2
+*-g++*:QMAKE_CXXFLAGS_RELEASE += -O3
+
+HEADERS += \
+ Alignment.h \
+ AlwaysInline.h \
+ ArrayBuffer.h \
+ ArrayBufferView.h \
+ ASCIICType.h \
+ Assertions.h \
+ Atomics.h \
+ AVLTree.h \
+ Bitmap.h \
+ BitVector.h \
+ BloomFilter.h \
+ BoundsCheckedPointer.h \
+ BumpPointerAllocator.h \
+ ByteArray.h \
+ CheckedArithmetic.h \
+ Compiler.h \
+ CryptographicallyRandomNumber.h \
+ CurrentTime.h \
+ DateMath.h \
+ DecimalNumber.h \
+ Decoder.h \
+ Deque.h \
+ DisallowCType.h \
+ dtoa.h \
+ dtoa/bignum-dtoa.h \
+ dtoa/bignum.h \
+ dtoa/cached-powers.h \
+ dtoa/diy-fp.h \
+ dtoa/double-conversion.h \
+ dtoa/double.h \
+ dtoa/fast-dtoa.h \
+ dtoa/fixed-dtoa.h \
+ dtoa/strtod.h \
+ dtoa/utils.h \
+ DynamicAnnotations.h \
+ Encoder.h \
+ FastAllocBase.h \
+ FastMalloc.h \
+ FixedArray.h \
+ Float32Array.h \
+ Float64Array.h \
+ Forward.h \
+ Functional.h \
+ GetPtr.h \
+ HashCountedSet.h \
+ HashFunctions.h \
+ HashIterators.h \
+ HashMap.h \
+ HashSet.h \
+ HashTable.h \
+ HashTraits.h \
+ HexNumber.h \
+ Int16Array.h \
+ Int32Array.h \
+ Int8Array.h \
+ ListHashSet.h \
+ ListRefPtr.h \
+ Locker.h \
+ MainThread.h \
+ MallocZoneSupport.h \
+ MathExtras.h \
+ MD5.h \
+ MessageQueue.h \
+ MetaAllocator.h \
+ MetaAllocatorHandle.h \
+ Noncopyable.h \
+ NonCopyingSort.h \
+ NotFound.h \
+ NullPtr.h \
+ OSAllocator.h \
+ OSRandomSource.h \
+ OwnArrayPtr.h \
+ OwnFastMallocPtr.h \
+ OwnPtr.h \
+ OwnPtrCommon.h \
+ PackedIntVector.h \
+ PageAllocation.h \
+ PageAllocationAligned.h \
+ PageBlock.h \
+ PageReservation.h \
+ ParallelJobs.h \
+ ParallelJobsGeneric.h \
+ ParallelJobsLibdispatch.h \
+ ParallelJobsOpenMP.h \
+ PassOwnArrayPtr.h \
+ PassOwnPtr.h \
+ PassRefPtr.h \
+ PassTraits.h \
+ Platform.h \
+ PossiblyNull.h \
+ qt/UtilsQt.h \
+ RandomNumber.h \
+ RandomNumberSeed.h \
+ RedBlackTree.h \
+ RefCounted.h \
+ RefCountedLeakCounter.h \
+ RefPtr.h \
+ RefPtrHashMap.h \
+ RetainPtr.h \
+ SHA1.h \
+ Spectrum.h \
+ StackBounds.h \
+ StaticConstructors.h \
+ StdLibExtras.h \
+ StringExtras.h \
+ StringHasher.h \
+ TCPackedCache.h \
+ TCSpinLock.h \
+ TCSystemAlloc.h \
+ text/ASCIIFastPath.h \
+ text/AtomicString.h \
+ text/AtomicStringHash.h \
+ text/AtomicStringImpl.h \
+ text/CString.h \
+ text/StringBuffer.h \
+ text/StringBuilder.h \
+ text/StringConcatenate.h \
+ text/StringHash.h \
+ text/StringImpl.h \
+ text/StringOperators.h \
+ text/TextPosition.h \
+ text/WTFString.h \
+ Threading.h \
+ ThreadingPrimitives.h \
+ ThreadRestrictionVerifier.h \
+ ThreadSafeRefCounted.h \
+ ThreadSpecific.h \
+ TypeTraits.h \
+ Uint16Array.h \
+ Uint32Array.h \
+ Uint8Array.h \
+ unicode/CharacterNames.h \
+ unicode/Collator.h \
+ unicode/icu/UnicodeIcu.h \
+ unicode/qt4/UnicodeQt4.h \
+ unicode/ScriptCodesFromICU.h \
+ unicode/Unicode.h \
+ unicode/UnicodeMacrosFromICU.h \
+ unicode/UTF8.h \
+ UnusedParam.h \
+ ValueCheck.h \
+ Vector.h \
+ VectorTraits.h \
+ VMTags.h \
+ WTFThreadData.h
+
+
+unix: HEADERS += ThreadIdentifierDataPthreads.h
+
+SOURCES += \
+ ArrayBuffer.cpp \
+ ArrayBufferView.cpp \
+ Assertions.cpp \
+ BitVector.cpp \
+ ByteArray.cpp \
+ CryptographicallyRandomNumber.cpp \
+ CurrentTime.cpp \
+ DateMath.cpp \
+ DecimalNumber.cpp \
+ dtoa.cpp \
+ dtoa/bignum-dtoa.cc \
+ dtoa/bignum.cc \
+ dtoa/cached-powers.cc \
+ dtoa/diy-fp.cc \
+ dtoa/double-conversion.cc \
+ dtoa/fast-dtoa.cc \
+ dtoa/fixed-dtoa.cc \
+ dtoa/strtod.cc \
+ FastMalloc.cpp \
+ gobject/GOwnPtr.cpp \
+ gobject/GRefPtr.cpp \
+ HashTable.cpp \
+ MD5.cpp \
+ MainThread.cpp \
+ MetaAllocator.cpp \
+ NullPtr.cpp \
+ OSRandomSource.cpp \
+ qt/MainThreadQt.cpp \
+ qt/StringQt.cpp \
+ PageAllocationAligned.cpp \
+ PageBlock.cpp \
+ ParallelJobsGeneric.cpp \
+ RandomNumber.cpp \
+ RefCountedLeakCounter.cpp \
+ SHA1.cpp \
+ StackBounds.cpp \
+ TCSystemAlloc.cpp \
+ Threading.cpp \
+ TypeTraits.cpp \
+ WTFThreadData.cpp \
+ text/AtomicString.cpp \
+ text/CString.cpp \
+ text/StringBuilder.cpp \
+ text/StringImpl.cpp \
+ text/StringStatics.cpp \
+ text/WTFString.cpp \
+ unicode/CollatorDefault.cpp \
+ unicode/icu/CollatorICU.cpp \
+ unicode/UTF8.cpp
+
+unix: SOURCES += \
+ OSAllocatorPosix.cpp \
+ ThreadIdentifierDataPthreads.cpp \
+ ThreadingPthreads.cpp
+
+win*|wince*: SOURCES += \
+ OSAllocatorWin.cpp \
+ ThreadSpecificWin.cpp \
+ ThreadingWin.cpp
+
+*sh4* {
+ QMAKE_CXXFLAGS += -mieee -w
+ QMAKE_CFLAGS += -mieee -w
+}
+
+lessThan(QT_GCC_MAJOR_VERSION, 5) {
+ # GCC 4.5 and before
+ lessThan(QT_GCC_MINOR_VERSION, 6) {
+ # Disable C++0x mode in JSC for those who enabled it in their Qt's mkspec.
+ *-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x
+ }
+
+ # GCC 4.6 and after.
+ greaterThan(QT_GCC_MINOR_VERSION, 5) {
+ if (!contains(QMAKE_CXXFLAGS, -std=c++0x) && !contains(QMAKE_CXXFLAGS, -std=gnu++0x)) {
+ # We need to deactivate those warnings because some names conflicts with upcoming c++0x types (e.g.nullptr).
+ QMAKE_CFLAGS_WARN_ON += -Wno-c++0x-compat
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-c++0x-compat
+ QMAKE_CFLAGS += -Wno-c++0x-compat
+ QMAKE_CXXFLAGS += -Wno-c++0x-compat
+ }
+ }
+}
diff --git a/Source/JavaScriptCore/wtf/wx/MainThreadWx.cpp b/Source/JavaScriptCore/wtf/wx/MainThreadWx.cpp
new file mode 100644
index 000000000..e1d15c96f
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wx/MainThreadWx.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#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()
+{
+}
+
+void scheduleDispatchFunctionsOnMainThread()
+{
+ wxCallAfter();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/wtf/wx/StringWx.cpp b/Source/JavaScriptCore/wtf/wx/StringWx.cpp
new file mode 100644
index 000000000..d5f6c578a
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/wx/StringWx.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 Vaclav Slavik, Kevin Ollivier <kevino@theolliviers.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.
+ *
+ * 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"
+
+// The wx headers must come first in this case, because the wtf/text headers
+// import windows.h, and we need to allow the wx headers to set its configuration
+// first.
+#include <wx/defs.h>
+#include <wx/string.h>
+
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+String::String(const wxString& wxstr)
+{
+#if !wxUSE_UNICODE
+ #error "This code only works in Unicode build of wxWidgets"
+#endif
+
+#if SIZEOF_WCHAR_T == 2
+
+ const UChar* str = wxstr.wc_str();
+ const size_t len = wxstr.length();
+
+#else // SIZEOF_WCHAR_T == 4
+
+ // NB: we can't simply use wxstr.mb_str(wxMBConvUTF16()) here because
+ // the number of characters in UTF-16 encoding of the string may differ
+ // from the number of UTF-32 values and we can't get the length from
+ // returned buffer:
+
+#if defined(wxUSE_UNICODE_UTF8) && wxUSE_UNICODE_UTF8
+ // in wx3's UTF8 mode, wc_str() returns a buffer, not raw pointer
+ wxWCharBuffer wideString(wxstr.wc_str());
+#else
+ const wxChar *wideString = wxstr.wc_str();
+#endif
+ size_t wideLength = wxstr.length();
+
+ wxMBConvUTF16 conv;
+
+ const size_t utf16bufLen = conv.FromWChar(0, 0, wideString, wideLength);
+ wxCharBuffer utf16buf(utf16bufLen);
+
+ const UChar* str = (const UChar*)utf16buf.data();
+ size_t len = conv.FromWChar(utf16buf.data(), utf16bufLen, wideString, wideLength) / 2;
+
+#endif // SIZEOF_WCHAR_T == 2
+
+ m_impl = StringImpl::create(str, len);
+
+}
+
+String::operator wxString() const
+{
+ return wxString(utf8().data(), wxConvUTF8);
+}
+
+} // namespace WTF