diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
commit | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch) | |
tree | 4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /JavaScriptCore/wtf | |
parent | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff) | |
download | external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'JavaScriptCore/wtf')
63 files changed, 6242 insertions, 1486 deletions
diff --git a/JavaScriptCore/wtf/ASCIICType.h b/JavaScriptCore/wtf/ASCIICType.h index 990c1ea..b1ee3dc 100644 --- a/JavaScriptCore/wtf/ASCIICType.h +++ b/JavaScriptCore/wtf/ASCIICType.h @@ -29,6 +29,7 @@ #ifndef WTF_ASCIICType_h #define WTF_ASCIICType_h +#include <wtf/Assertions.h> #include <wtf/Platform.h> // The behavior of many of the functions in the <ctype.h> header is dependent @@ -50,7 +51,6 @@ namespace WTF { #endif inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } -// ANDROID: extra parentheses around expressions to suppress warnings inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } #if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) @@ -72,6 +72,13 @@ namespace WTF { #endif inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } + inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } + inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) + inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } +#endif + inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } + inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } #if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) @@ -87,19 +94,18 @@ namespace WTF { inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } /* - Statistics from a run of the PLT on the usage of isASCIISpace: - Hex Name Count - --- ---- ----- - ALL OTHER VALUES 689383 - x20 SPACE 294720 - x0A NEWLINE 89059 - x09 TAB 28320 - x0D CARRIAGE RETURN 0 - x0C FORMFEED 0 - x0B VERTICAL TAB 0 - + 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 */ - inline bool isASCIISpace(char c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } inline bool isASCIISpace(unsigned short c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } #if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) @@ -121,6 +127,19 @@ namespace WTF { #endif inline int toASCIIUpper(int c) { return static_cast<int>(c & ~((c >= 'a' && c <= 'z') << 5)); } + inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) + inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } +#endif + inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + + inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } + inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) + inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } +#endif + inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } } #endif diff --git a/JavaScriptCore/wtf/AVLTree.h b/JavaScriptCore/wtf/AVLTree.h new file mode 100644 index 0000000..cd1511f --- /dev/null +++ b/JavaScriptCore/wtf/AVLTree.h @@ -0,0 +1,958 @@ +/* + * 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 KJS_AVL_TREE_H_ +#define KJS_AVL_TREE_H_ + +#include "Assertions.h" + +namespace JSC { + +// 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: + bool m_data[maxDepth]; +}; + +// 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; + + 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, false) : get_gt(h, false); + } + + 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, false)); + set_gt(h, get_gt(rm, false)); + 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, false)); + set_gt(new_node, get_gt(h, false)); + 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/JavaScriptCore/wtf/AlwaysInline.h b/JavaScriptCore/wtf/AlwaysInline.h index 3f54815..d39b2b9 100644 --- a/JavaScriptCore/wtf/AlwaysInline.h +++ b/JavaScriptCore/wtf/AlwaysInline.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * 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 @@ -18,8 +18,10 @@ * */ +#include "Platform.h" + #ifndef ALWAYS_INLINE -#if COMPILER(GCC) && defined(NDEBUG) +#if COMPILER(GCC) && defined(NDEBUG) && !COMPILER(MINGW) #define ALWAYS_INLINE inline __attribute__ ((__always_inline__)) #elif COMPILER(MSVC) && defined(NDEBUG) #define ALWAYS_INLINE __forceinline @@ -35,3 +37,19 @@ #define NEVER_INLINE #endif #endif + +#ifndef UNLIKELY +#if COMPILER(GCC) +#define UNLIKELY(x) __builtin_expect((x), 0) +#else +#define UNLIKELY(x) (x) +#endif +#endif + +#ifndef LIKELY +#if COMPILER(GCC) +#define LIKELY(x) __builtin_expect((x), 1) +#else +#define LIKELY(x) (x) +#endif +#endif diff --git a/JavaScriptCore/wtf/Assertions.cpp b/JavaScriptCore/wtf/Assertions.cpp index 43f3ef7..98de91c 100644 --- a/JavaScriptCore/wtf/Assertions.cpp +++ b/JavaScriptCore/wtf/Assertions.cpp @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. * @@ -21,7 +20,7 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index 74ea91c..8449563 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -1,4 +1,3 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ /* * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. * @@ -83,9 +82,9 @@ #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 %@. +/* 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 @@ -154,7 +153,7 @@ while (0) CRASH(); \ } \ while (0) -#endif // COMPILER(MSVC7) +#endif /* COMPILER(MSVC7) */ #define ASSERT_NOT_REACHED() do { \ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \ CRASH(); \ @@ -229,4 +228,4 @@ while (0) #define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) #endif -#endif // WTF_Assertions_h +#endif /* WTF_Assertions_h */ diff --git a/JavaScriptCore/wtf/Deque.h b/JavaScriptCore/wtf/Deque.h index c09ef42..70c546b 100644 --- a/JavaScriptCore/wtf/Deque.h +++ b/JavaScriptCore/wtf/Deque.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * 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 @@ -25,99 +25,565 @@ * (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 -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> +// FIXME: Could move what Vector and Deque share into a separate file. +// Deque doesn't actually use Vector. + +#include "Vector.h" namespace WTF { + template<typename T> class DequeIteratorBase; + template<typename T> class DequeIterator; + template<typename T> class DequeConstIterator; + template<typename T> class DequeReverseIterator; + template<typename T> class DequeConstReverseIterator; + template<typename T> - class DequeNode { + class Deque { public: - DequeNode(const T& item) : m_value(item), m_next(0) { } + typedef DequeIterator<T> iterator; + typedef DequeConstIterator<T> const_iterator; + typedef DequeReverseIterator<T> reverse_iterator; + typedef DequeConstReverseIterator<T> const_reverse_iterator; + + Deque(); + Deque(const Deque<T>&); + Deque& operator=(const Deque<T>&); + ~Deque(); + + void swap(Deque<T>&); + + 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]; } + + template<typename U> void append(const U&); + template<typename U> void prepend(const U&); + void removeFirst(); + + void clear(); + + private: + friend class DequeIteratorBase<T>; + + typedef VectorBuffer<T, 0> Buffer; + typedef VectorTypeOperations<T> TypeOperations; + typedef DequeIteratorBase<T> IteratorBase; + + 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> + class DequeIteratorBase { + private: + typedef DequeIteratorBase<T> Base; + + protected: + DequeIteratorBase(); + DequeIteratorBase(const Deque<T>*, 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; - T m_value; - DequeNode* m_next; + bool isEqual(const Base&) const; + + private: + void addToIteratorsList(); + void checkValidity() const; + void checkValidity(const Base&) const; + + Deque<T>* m_deque; + size_t m_index; + + friend class Deque<T>; + +#ifndef NDEBUG + mutable DequeIteratorBase* m_next; + mutable DequeIteratorBase* m_previous; +#endif }; template<typename T> - class Deque : Noncopyable { + class DequeIterator : public DequeIteratorBase<T> { + private: + typedef DequeIteratorBase<T> Base; + typedef DequeIterator<T> Iterator; + public: - Deque() - : m_size(0) - , m_first(0) - , m_last(0) - { + DequeIterator(Deque<T>* 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> + class DequeConstIterator : public DequeIteratorBase<T> { + private: + typedef DequeIteratorBase<T> Base; + typedef DequeConstIterator<T> Iterator; + typedef DequeIterator<T> NonConstIterator; + + public: + DequeConstIterator(const Deque<T>* 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> + class DequeReverseIterator : public DequeIteratorBase<T> { + private: + typedef DequeIteratorBase<T> Base; + typedef DequeReverseIterator<T> Iterator; + + public: + DequeReverseIterator(const Deque<T>* 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> + class DequeConstReverseIterator : public DequeIteratorBase<T> { + private: + typedef DequeIteratorBase<T> Base; + typedef DequeConstReverseIterator<T> Iterator; + typedef DequeReverseIterator<T> NonConstIterator; + + public: + DequeConstReverseIterator(const Deque<T>* 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> inline void Deque<T>::checkValidity() const { } + template<typename T> inline void Deque<T>::checkIndexValidity(size_t) const { } + template<typename T> inline void Deque<T>::invalidateIterators() { } +#else + template<typename T> + void Deque<T>::checkValidity() const + { + if (!m_buffer.capacity()) { + ASSERT(!m_start); + ASSERT(!m_end); + } else { + ASSERT(m_start < m_buffer.capacity()); + ASSERT(m_end < m_buffer.capacity()); } + } - ~Deque() - { - clear(); + template<typename T> + void Deque<T>::checkIndexValidity(size_t index) const + { + ASSERT(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); } + } - size_t size() const { return m_size; } - bool isEmpty() const { return !size(); } - - void append(const T& item) - { - DequeNode<T>* newNode = new DequeNode<T>(item); - if (m_last) - m_last->m_next = newNode; - m_last = newNode; - if (!m_first) - m_first = newNode; - ++m_size; + template<typename T> + void Deque<T>::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> + inline Deque<T>::Deque() + : m_start(0) + , m_end(0) +#ifndef NDEBUG + , m_iterators(0) +#endif + { + checkValidity(); + } - void prepend(const T& item) - { - DequeNode<T>* newNode = new DequeNode<T>(item); - newNode->m_next = m_first; - m_first = newNode; - if (!m_last) - m_last = newNode; - ++m_size; + template<typename T> + inline Deque<T>::Deque(const Deque<T>& 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); } + } - T& first() { ASSERT(m_first); return m_first->m_value; } - const T& first() const { ASSERT(m_first); return m_first->m_value; } - T& last() { ASSERT(m_last); return m_last->m_value; } - const T& last() const { ASSERT(m_last); return m_last->m_value; } - - void removeFirst() - { - ASSERT(m_first); - if (DequeNode<T>* n = m_first) { - m_first = m_first->m_next; - if (n == m_last) - m_last = 0; - - m_size--; - delete n; - } + template<typename T> + void deleteAllValues(const Deque<T>& collection) + { + typedef typename Deque<T>::const_iterator iterator; + iterator end = collection.end(); + for (iterator it = collection.begin(); it != end; ++it) + delete *it; + } + + template<typename T> + inline Deque<T>& Deque<T>::operator=(const Deque<T>& other) + { + Deque<T> copy(other); + swap(copy); + return *this; + } + + template<typename T> + inline void Deque<T>::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> + inline Deque<T>::~Deque() + { + checkValidity(); + invalidateIterators(); + destroyAll(); + } + + template <typename T> + inline void Deque<T>::swap(Deque<T>& 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> + inline void Deque<T>::clear() + { + checkValidity(); + invalidateIterators(); + destroyAll(); + m_start = 0; + m_end = 0; + checkValidity(); + } + + template<typename T> + inline void Deque<T>::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> + void Deque<T>::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(); + } - void clear() - { - DequeNode<T>* n = m_first; - m_first = 0; - m_last = 0; - m_size = 0; - while (n) { - DequeNode<T>* next = n->m_next; - delete n; - n = next; + template<typename T> template<typename U> + inline void Deque<T>::append(const U& value) + { + checkValidity(); + expandCapacityIfNeeded(); + new (&m_buffer.buffer()[m_end]) T(value); + if (m_end == m_buffer.capacity() - 1) + m_end = 0; + else + ++m_end; + checkValidity(); + } + + template<typename T> template<typename U> + inline void Deque<T>::prepend(const U& value) + { + checkValidity(); + expandCapacityIfNeeded(); + if (!m_start) + m_start = m_buffer.capacity() - 1; + else + --m_start; + new (&m_buffer.buffer()[m_start]) T(value); + checkValidity(); + } + + template<typename T> + inline void Deque<T>::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(); + } + +#ifdef NDEBUG + template<typename T> inline void DequeIteratorBase<T>::checkValidity() const { } + template<typename T> inline void DequeIteratorBase<T>::checkValidity(const DequeIteratorBase<T>&) const { } + template<typename T> inline void DequeIteratorBase<T>::addToIteratorsList() { } +#else + template<typename T> + void DequeIteratorBase<T>::checkValidity() const + { + ASSERT(m_deque); + m_deque->checkIndexValidity(m_index); + } + + template<typename T> + void DequeIteratorBase<T>::checkValidity(const Base& other) const + { + checkValidity(); + other.checkValidity(); + ASSERT(m_deque == other.m_deque); + } + + template<typename T> + void DequeIteratorBase<T>::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; + } +#endif + + template<typename T> + inline DequeIteratorBase<T>::DequeIteratorBase() + : m_deque(0) + { + } + + template<typename T> + inline DequeIteratorBase<T>::DequeIteratorBase(const Deque<T>* deque, size_t index) + : m_deque(const_cast<Deque<T>*>(deque)) + , m_index(index) + { + addToIteratorsList(); + checkValidity(); + } + + template<typename T> + inline DequeIteratorBase<T>::DequeIteratorBase(const Base& other) + : m_deque(other.m_deque) + , m_index(other.m_index) + { + addToIteratorsList(); + checkValidity(); + } + + template<typename T> + inline DequeIteratorBase<T>::~DequeIteratorBase() + { +#ifndef NDEBUG + // Delete iterator from doubly-linked list of iterators. + if (!m_deque) { + ASSERT(!m_next); + ASSERT(!m_previous); + } else { + if (m_next) { + ASSERT(m_next->m_previous == this); + m_next->m_previous = m_previous; + } + if (m_previous) { + ASSERT(m_deque->m_iterators != this); + ASSERT(m_previous->m_next == this); + m_previous->m_next = m_next; + } else { + ASSERT(m_deque->m_iterators == this); + m_deque->m_iterators = m_next; } } + m_deque = 0; + m_next = 0; + m_previous = 0; +#endif + } - private: - size_t m_size; - DequeNode<T>* m_first; - DequeNode<T>* m_last; + template<typename T> + inline bool DequeIteratorBase<T>::isEqual(const Base& other) const + { + checkValidity(other); + return m_index == other.m_index; + } - }; + template<typename T> + inline void DequeIteratorBase<T>::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> + inline void DequeIteratorBase<T>::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> + inline T* DequeIteratorBase<T>::after() const + { + checkValidity(); + ASSERT(m_index != m_deque->m_end); + return &m_deque->m_buffer.buffer()[m_index]; + } + + template<typename T> + inline T* DequeIteratorBase<T>::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 diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 69df95e..8f7d5ef 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2005, 2007, The Android Open Source Project // All rights reserved. +// Copyright (C) 2005, 2006, 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 @@ -77,7 +78,7 @@ #include "FastMalloc.h" #include "Assertions.h" -#if USE(MULTIPLE_THREADS) +#if ENABLE(JSC_MULTIPLE_THREADS) #include <pthread.h> #endif @@ -93,10 +94,12 @@ #define FORCE_SYSTEM_MALLOC 1 #endif +#define TCMALLOC_TRACK_DECOMMITED_SPANS (HAVE(VIRTUALALLOC)) + #ifndef NDEBUG namespace WTF { -#if USE(MULTIPLE_THREADS) +#if ENABLE(JSC_MULTIPLE_THREADS) static pthread_key_t isForbiddenKey; static pthread_once_t isForbiddenKeyOnce = PTHREAD_ONCE_INIT; static void initializeIsForbiddenKey() @@ -139,7 +142,7 @@ void fastMallocAllow() { staticIsForbidden = false; } -#endif // USE(MULTIPLE_THREADS) +#endif // ENABLE(JSC_MULTIPLE_THREADS) } // namespace WTF #endif // NDEBUG @@ -147,53 +150,111 @@ void fastMallocAllow() #include <string.h> namespace WTF { -void *fastZeroedMalloc(size_t n) + +void* fastZeroedMalloc(size_t n) { - void *result = fastMalloc(n); - if (!result) - return 0; + void* result = fastMalloc(n); memset(result, 0, n); -#ifndef WTF_CHANGES - MallocHook::InvokeNewHook(result, n); -#endif return result; } +void* tryFastZeroedMalloc(size_t n) +{ + void* result = tryFastMalloc(n); + if (!result) + return 0; + memset(result, 0, n); + return result; } +} // namespace WTF + #if FORCE_SYSTEM_MALLOC #include <stdlib.h> #if !PLATFORM(WIN_OS) #include <pthread.h> +#else + #include "windows.h" #endif namespace WTF { - -void *fastMalloc(size_t n) + +void* tryFastMalloc(size_t n) { ASSERT(!isForbidden()); return malloc(n); } -void *fastCalloc(size_t n_elements, size_t element_size) +void* fastMalloc(size_t n) +{ + ASSERT(!isForbidden()); + void* result = malloc(n); + if (!result) + abort(); + return result; +} + +void* tryFastCalloc(size_t n_elements, size_t element_size) { ASSERT(!isForbidden()); return calloc(n_elements, element_size); } +void* fastCalloc(size_t n_elements, size_t element_size) +{ + ASSERT(!isForbidden()); + void* result = calloc(n_elements, element_size); + if (!result) + abort(); + return result; +} + void fastFree(void* p) { ASSERT(!isForbidden()); free(p); } -void *fastRealloc(void* p, size_t n) +void* tryFastRealloc(void* p, size_t n) { ASSERT(!isForbidden()); return realloc(p, n); } +void* fastRealloc(void* p, size_t n) +{ + ASSERT(!isForbidden()); + void* result = realloc(p, n); + if (!result) + abort(); + return result; +} + +void releaseFastMallocFreeMemory() { } + +#if HAVE(VIRTUALALLOC) +void* fastMallocExecutable(size_t n) +{ + return VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +} + +void fastFreeExecutable(void* p) +{ + VirtualFree(p, 0, MEM_RELEASE); +} +#else +void* fastMallocExecutable(size_t n) +{ + return fastMalloc(n); +} + +void fastFreeExecutable(void* p) +{ + fastFree(p); +} +#endif + } // namespace WTF #if PLATFORM(DARWIN) @@ -202,7 +263,7 @@ void *fastRealloc(void* p, size_t n) extern "C" const int jscore_fastmalloc_introspection = 0; #endif -#else +#else // FORCE_SYSTEM_MALLOC #if HAVE(STDINT_H) #include <stdint.h> @@ -236,6 +297,7 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #if PLATFORM(DARWIN) #include "MallocZoneSupport.h" +#include <wtf/HashSet.h> #endif #ifndef PRIuS @@ -290,7 +352,7 @@ public: 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*) { } + 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*); @@ -859,9 +921,12 @@ struct Span { 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 @@ -872,6 +937,12 @@ struct Span { #endif }; +#if TCMALLOC_TRACK_DECOMMITED_SPANS +#define ASSERT_SPAN_COMMITTED(span) ASSERT(!span->decommitted) +#else +#define ASSERT_SPAN_COMMITTED(span) +#endif + #ifdef SPAN_HISTORY void Event(Span* span, char op, int v = 0) { span->history[span->nexthistory] = op; @@ -1173,13 +1244,22 @@ inline Span* TCMalloc_PageHeap::New(Length n) { Span* result = ll->next; Carve(result, n, released); +#if TCMALLOC_TRACK_DECOMMITED_SPANS + if (result->decommitted) { + TCMalloc_SystemCommit(reinterpret_cast<void*>(result->start << kPageShift), static_cast<size_t>(n << kPageShift)); + result->decommitted = false; + } +#endif ASSERT(Check()); free_pages_ -= n; return result; } Span* result = AllocLarge(n); - if (result != NULL) return result; + if (result != NULL) { + ASSERT_SPAN_COMMITTED(result); + return result; + } // Grow the heap and try again if (!GrowHeap(n)) { @@ -1226,6 +1306,12 @@ Span* TCMalloc_PageHeap::AllocLarge(Length n) { if (best != NULL) { Carve(best, n, from_released); +#if TCMALLOC_TRACK_DECOMMITED_SPANS + if (best->decommitted) { + TCMalloc_SystemCommit(reinterpret_cast<void*>(best->start << kPageShift), static_cast<size_t>(n << kPageShift)); + best->decommitted = false; + } +#endif ASSERT(Check()); free_pages_ -= n; return best; @@ -1250,6 +1336,15 @@ Span* TCMalloc_PageHeap::Split(Span* span, Length n) { return leftover; } +#if !TCMALLOC_TRACK_DECOMMITED_SPANS +static ALWAYS_INLINE void propagateDecommittedState(Span*, Span*) { } +#else +static ALWAYS_INLINE void propagateDecommittedState(Span* destination, Span* source) +{ + destination->decommitted = source->decommitted; +} +#endif + inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) { ASSERT(n > 0); DLL_Remove(span); @@ -1261,6 +1356,7 @@ inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) { if (extra > 0) { Span* leftover = NewSpan(span->start + n, extra); leftover->free = 1; + propagateDecommittedState(leftover, span); Event(leftover, 'S', extra); RecordSpan(leftover); @@ -1274,6 +1370,16 @@ inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) { } } +#if !TCMALLOC_TRACK_DECOMMITED_SPANS +static ALWAYS_INLINE void mergeDecommittedStates(Span*, Span*) { } +#else +static ALWAYS_INLINE void mergeDecommittedStates(Span* destination, Span* other) +{ + if (other->decommitted) + destination->decommitted = true; +} +#endif + inline void TCMalloc_PageHeap::Delete(Span* span) { ASSERT(Check()); ASSERT(!span->free); @@ -1281,7 +1387,9 @@ inline void TCMalloc_PageHeap::Delete(Span* span) { 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 @@ -1298,6 +1406,7 @@ inline void TCMalloc_PageHeap::Delete(Span* span) { // Merge preceding span into this span ASSERT(prev->start + prev->length == p); const Length len = prev->length; + mergeDecommittedStates(span, prev); DLL_Remove(prev); DeleteSpan(prev); span->start -= len; @@ -1310,6 +1419,7 @@ inline void TCMalloc_PageHeap::Delete(Span* span) { // Merge next span into this span ASSERT(next->start == p+n); const Length len = next->length; + mergeDecommittedStates(span, next); DLL_Remove(next); DeleteSpan(next); span->length += len; @@ -1350,6 +1460,9 @@ void TCMalloc_PageHeap::IncrementalScavenge(Length n) { DLL_Remove(s); TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift), static_cast<size_t>(s->length << kPageShift)); +#if TCMALLOC_TRACK_DECOMMITED_SPANS + s->decommitted = true; +#endif DLL_Prepend(&slist->returned, s); scavenge_counter_ = std::max<size_t>(64UL, std::min<size_t>(kDefaultReleaseDelay, kDefaultReleaseDelay - (free_pages_ / kDefaultReleaseDelay))); @@ -1456,7 +1569,7 @@ bool TCMalloc_PageHeap::GrowHeap(Length n) { if (n < ask) { // Try growing just "n" pages ask = n; - ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize);; + ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize); } if (ptr == NULL) return false; } @@ -1717,13 +1830,18 @@ class TCMalloc_Central_FreeList { #ifdef WTF_CHANGES template <class Finder, class Reader> - void enumerateFreeObjects(Finder& finder, const Reader& 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); - for (Span* span = reader(nonempty_.next); span && span != &nonempty_; span = (span->next ? reader(span->next) : 0)) { + 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(reinterpret_cast<void**>(nextObject))) finder.visit(nextObject); } @@ -2090,6 +2208,7 @@ void* TCMalloc_Central_FreeList::FetchFromSpans() { Span* span = nonempty_.next; ASSERT(span->objects != NULL); + ASSERT_SPAN_COMMITTED(span); span->refcount++; void* result = span->objects; span->objects = *(reinterpret_cast<void**>(result)); @@ -2120,6 +2239,7 @@ ALWAYS_INLINE void TCMalloc_Central_FreeList::Populate() { 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 @@ -2896,11 +3016,15 @@ static inline void* CheckedMallocResult(void *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 abortOnFailure> +#endif static ALWAYS_INLINE void* do_malloc(size_t size) { void* ret = NULL; @@ -2930,7 +3054,14 @@ static ALWAYS_INLINE void* do_malloc(size_t size) { // size-appropriate freelist, afer replenishing it if it's empty. ret = CheckedMallocResult(heap->Allocate(size)); } - if (ret == NULL) errno = ENOMEM; + if (!ret) { +#ifdef WTF_CHANGES + if (abortOnFailure) // This branch should be optimized out by the compiler. + abort(); +#else + errno = ENOMEM; +#endif + } return ret; } @@ -2947,7 +3078,9 @@ static ALWAYS_INLINE void do_free(void* ptr) { 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); @@ -2960,11 +3093,13 @@ static ALWAYS_INLINE void do_free(void* ptr) { 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); } } @@ -3090,6 +3225,24 @@ static inline struct mallinfo do_mallinfo() { #ifndef WTF_CHANGES extern "C" +#else +#define do_malloc do_malloc<abortOnFailure> + +template <bool abortOnFailure> +void* malloc(size_t); + +void* fastMalloc(size_t size) +{ + return malloc<true>(size); +} + +void* tryFastMalloc(size_t size) +{ + return malloc<false>(size); +} + +template <bool abortOnFailure> +ALWAYS_INLINE #endif void* malloc(size_t size) { void* result = do_malloc(size); @@ -3111,6 +3264,22 @@ void free(void* ptr) { #ifndef WTF_CHANGES extern "C" +#else +template <bool abortOnFailure> +void* calloc(size_t, size_t); + +void* fastCalloc(size_t n, size_t elem_size) +{ + return calloc<true>(n, elem_size); +} + +void* tryFastCalloc(size_t n, size_t elem_size) +{ + return calloc<false>(n, elem_size); +} + +template <bool abortOnFailure> +ALWAYS_INLINE #endif void* calloc(size_t n, size_t elem_size) { const size_t totalBytes = n * elem_size; @@ -3141,6 +3310,22 @@ void cfree(void* ptr) { #ifndef WTF_CHANGES extern "C" +#else +template <bool abortOnFailure> +void* realloc(void*, size_t); + +void* fastRealloc(void* old_ptr, size_t new_size) +{ + return realloc<true>(old_ptr, new_size); +} + +void* tryFastRealloc(void* old_ptr, size_t new_size) +{ + return realloc<false>(old_ptr, new_size); +} + +template <bool abortOnFailure> +ALWAYS_INLINE #endif void* realloc(void* old_ptr, size_t new_size) { if (old_ptr == NULL) { @@ -3200,7 +3385,19 @@ void* realloc(void* old_ptr, size_t new_size) { } } -#ifndef WTF_CHANGES +void* fastMallocExecutable(size_t n) +{ + return malloc<false>(n); +} + +void fastFreeExecutable(void* p) +{ + free(p); +} + +#ifdef WTF_CHANGES +#undef do_malloc +#else static SpinLock set_new_handler_lock = SPINLOCK_INITIALIZER; @@ -3412,7 +3609,6 @@ void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; #endif #if defined(WTF_CHANGES) && PLATFORM(DARWIN) -#include <wtf/HashSet.h> class FreeObjectFinder { const RemoteMemoryReader& m_reader; @@ -3431,10 +3627,10 @@ public: threadCache->enumerateFreeObjects(*this, m_reader); } - void findFreeObjects(TCMalloc_Central_FreeListPadded* centralFreeList, size_t numSizes) + 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); + centralFreeList[i].enumerateFreeObjects(*this, m_reader, remoteCentralFreeList + i); } }; @@ -3548,7 +3744,7 @@ kern_return_t FastMallocZone::enumerate(task_t task, void* context, unsigned typ FreeObjectFinder finder(memoryReader); finder.findFreeObjects(threadHeaps); - finder.findFreeObjects(centralCaches, kNumClasses); + finder.findFreeObjects(centralCaches, kNumClasses, mzone->m_centralCaches); TCMalloc_PageHeap::PageMap* pageMap = &pageHeap->pagemap_; PageMapFreeObjectFinder pageMapFinder(memoryReader, finder); @@ -3625,8 +3821,14 @@ void FastMallocZone::init() #endif +void releaseFastMallocFreeMemory() +{ + SpinLockHolder h(&pageheap_lock); + pageheap->ReleaseFreePages(); +} + #if WTF_CHANGES } // namespace WTF #endif -#endif // USE_SYSTEM_MALLOC +#endif // FORCE_SYSTEM_MALLOC diff --git a/JavaScriptCore/wtf/FastMalloc.h b/JavaScriptCore/wtf/FastMalloc.h index 27720e0..fb2762c 100644 --- a/JavaScriptCore/wtf/FastMalloc.h +++ b/JavaScriptCore/wtf/FastMalloc.h @@ -1,7 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * This file is part of the KDE libraries - * Copyright (C) 2005 Apple Computer, Inc. + * 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 @@ -29,23 +27,40 @@ namespace WTF { - void *fastMalloc(size_t n); - void *fastZeroedMalloc(size_t n); - void *fastCalloc(size_t n_elements, size_t element_size); + // These functions call abort() if an allocation fails. + void* fastMalloc(size_t n); + void* fastZeroedMalloc(size_t n); + void* fastCalloc(size_t n_elements, size_t element_size); + void* fastRealloc(void* p, size_t n); + + // These functions return NULL 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); + void fastFree(void* p); - void *fastRealloc(void* p, size_t n); + + void* fastMallocExecutable(size_t n); + void fastFreeExecutable(void* p); #ifndef NDEBUG void fastMallocForbid(); void fastMallocAllow(); #endif + void releaseFastMallocFreeMemory(); + } // namespace WTF using WTF::fastMalloc; using WTF::fastZeroedMalloc; using WTF::fastCalloc; using WTF::fastRealloc; +using WTF::tryFastMalloc; +using WTF::tryFastZeroedMalloc; +using WTF::tryFastCalloc; +using WTF::tryFastRealloc; using WTF::fastFree; #ifndef NDEBUG diff --git a/JavaScriptCore/wtf/GOwnPtr.cpp b/JavaScriptCore/wtf/GOwnPtr.cpp new file mode 100644 index 0000000..58869f4 --- /dev/null +++ b/JavaScriptCore/wtf/GOwnPtr.cpp @@ -0,0 +1,59 @@ +/* + * 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" + +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<GCond>(GCond* ptr) +{ + if (ptr) + g_cond_free(ptr); +} + +template <> void freeOwnedGPtr<GMutex>(GMutex* ptr) +{ + if (ptr) + g_mutex_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 diff --git a/JavaScriptCore/wtf/GOwnPtr.h b/JavaScriptCore/wtf/GOwnPtr.h new file mode 100644 index 0000000..bbb793a --- /dev/null +++ b/JavaScriptCore/wtf/GOwnPtr.h @@ -0,0 +1,97 @@ +/* + * 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 + +#include <algorithm> +#include <glib.h> +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> + +namespace WTF { + template <typename T> inline void freeOwnedGPtr(T* ptr) { g_free(reinterpret_cast<void*>(ptr)); } + template<> void freeOwnedGPtr<GError>(GError*); + template<> void freeOwnedGPtr<GList>(GList*); + template<> void freeOwnedGPtr<GCond>(GCond*); + template<> void freeOwnedGPtr<GMutex>(GMutex*); + template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*); + template<> void freeOwnedGPtr<GDir>(GDir*); + + template <typename T> class GOwnPtr : Noncopyable { + 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() { freeOwnedGPtr(m_ptr); m_ptr = 0; } + + T& operator*() const { ASSERT(m_ptr); return *m_ptr; } + T* operator->() const { ASSERT(m_ptr); return m_ptr; } + + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. + typedef T* 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(); + } + +} // namespace WTF + +using WTF::GOwnPtr; + +#endif // GOwnPtr_h diff --git a/JavaScriptCore/wtf/HashCountedSet.h b/JavaScriptCore/wtf/HashCountedSet.h index 202577a..8095a2b 100644 --- a/JavaScriptCore/wtf/HashCountedSet.h +++ b/JavaScriptCore/wtf/HashCountedSet.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * This file is part of the KDE libraries * Copyright (C) 2005 Apple Computer, Inc. @@ -25,6 +24,7 @@ #include "Assertions.h" #include "HashMap.h" +#include "Vector.h" namespace WTF { @@ -170,6 +170,33 @@ namespace WTF { { 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 diff --git a/JavaScriptCore/wtf/HashFunctions.h b/JavaScriptCore/wtf/HashFunctions.h index bf85dc0..2c66a2d 100644 --- a/JavaScriptCore/wtf/HashFunctions.h +++ b/JavaScriptCore/wtf/HashFunctions.h @@ -1,7 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * This file is part of the KDE libraries - * Copyright (C) 2005, 2006 Apple Computer, Inc. + * 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 @@ -37,6 +35,32 @@ namespace WTF { // 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); @@ -69,7 +93,15 @@ namespace WTF { }; template<typename T> struct FloatHash { - static unsigned hash(T key) { return intHash(*reinterpret_cast<typename IntTypes<sizeof(T)>::UnsignedType*>(&key)); } + 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; }; @@ -91,18 +123,36 @@ namespace WTF { static bool equal(T a, T b) { return a == b; } static const bool safeToCompareToEmptyOrDeleted = true; }; - template<typename P> struct PtrHash<RefPtr<P> > { - static unsigned hash(const RefPtr<P>& key) { return PtrHash<P*>::hash(key.get()); } + 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 const bool safeToCompareToEmptyOrDeleted = true; + 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; }; @@ -110,6 +160,10 @@ namespace WTF { 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; }; @@ -118,6 +172,8 @@ namespace WTF { 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; diff --git a/JavaScriptCore/wtf/HashIterators.h b/JavaScriptCore/wtf/HashIterators.h index c449112..682c83b 100644 --- a/JavaScriptCore/wtf/HashIterators.h +++ b/JavaScriptCore/wtf/HashIterators.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2007 Apple Inc. All rights reserved. * diff --git a/JavaScriptCore/wtf/HashMap.h b/JavaScriptCore/wtf/HashMap.h index 66d49d7..c5b75ff 100644 --- a/JavaScriptCore/wtf/HashMap.h +++ b/JavaScriptCore/wtf/HashMap.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * 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 @@ -34,7 +33,7 @@ namespace WTF { private: typedef KeyTraitsArg KeyTraits; typedef MappedTraitsArg MappedTraits; - typedef PairBaseHashTraits<KeyTraits, MappedTraits> ValueTraits; + typedef PairHashTraits<KeyTraits, MappedTraits> ValueTraits; public: typedef typename KeyTraits::TraitType KeyType; @@ -44,28 +43,13 @@ namespace WTF { private: typedef HashArg HashFunctions; - typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Hash StorageHashFunctions; - - typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Traits KeyStorageTraits; - typedef typename MappedTraits::StorageTraits MappedStorageTraits; - typedef PairHashTraits<KeyStorageTraits, MappedStorageTraits> ValueStorageTraits; - - typedef typename KeyStorageTraits::TraitType KeyStorageType; - typedef typename MappedStorageTraits::TraitType MappedStorageType; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - - typedef HashTable<KeyStorageType, ValueStorageType, PairFirstExtractor<ValueStorageType>, - StorageHashFunctions, ValueStorageTraits, KeyStorageTraits> HashTableType; + typedef HashTable<KeyType, ValueType, PairFirstExtractor<ValueType>, + HashFunctions, ValueTraits, KeyTraits> HashTableType; public: typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator; typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator; - HashMap(); - HashMap(const HashMap&); - HashMap& operator=(const HashMap&); - ~HashMap(); - void swap(HashMap&); int size() const; @@ -101,8 +85,6 @@ namespace WTF { private: pair<iterator, bool> inlineAdd(const KeyType&, const MappedType&); - void refAll(); - void derefAll(); HashTableType m_impl; }; @@ -111,98 +93,27 @@ namespace WTF { static const typename PairType::first_type& extract(const PairType& p) { return p.first; } }; - template<bool canReplaceDeletedKey, typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions> - struct HashMapTranslator; - - template<typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions> - struct HashMapTranslator<true, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> { + template<typename ValueType, typename ValueTraits, typename HashFunctions> + struct HashMapTranslator { typedef typename ValueType::first_type KeyType; typedef typename ValueType::second_type MappedType; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - typedef typename ValueStorageTraits::FirstTraits KeyStorageTraits; - typedef typename KeyStorageTraits::TraitType KeyStorageType; - typedef typename ValueStorageTraits::SecondTraits MappedStorageTraits; - typedef typename MappedStorageTraits::TraitType MappedStorageType; - typedef typename ValueTraits::FirstTraits KeyTraits; - typedef typename ValueTraits::SecondTraits MappedTraits; - - static unsigned hash(const KeyType& key) { return HashFunctions::hash(key); } - static bool equal(const KeyStorageType& a, const KeyType& b) { return HashFunctions::equal(*(KeyType*)&a, b); } - static void translate(ValueStorageType& location, const KeyType& key, const MappedType& mapped) - { - Assigner<KeyTraits::needsRef, KeyType, KeyStorageType, KeyTraits>::assign(key, location.first); - Assigner<MappedTraits::needsRef, MappedType, MappedStorageType, MappedTraits>::assign(mapped, location.second); - } - }; - template<typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions> - struct HashMapTranslator<false, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> { - typedef typename ValueType::first_type KeyType; - typedef typename ValueType::second_type MappedType; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - typedef typename ValueStorageTraits::FirstTraits KeyStorageTraits; - typedef typename KeyStorageTraits::TraitType KeyStorageType; - typedef typename ValueStorageTraits::SecondTraits MappedStorageTraits; - typedef typename MappedStorageTraits::TraitType MappedStorageType; - typedef typename ValueTraits::FirstTraits KeyTraits; - typedef typename ValueTraits::SecondTraits MappedTraits; - static unsigned hash(const KeyType& key) { return HashFunctions::hash(key); } - static bool equal(const KeyStorageType& a, const KeyType& b) { return HashFunctions::equal(*(KeyType*)&a, b); } - static void translate(ValueStorageType& location, const KeyType& key, const MappedType& mapped) + static bool equal(const KeyType& a, const KeyType& b) { return HashFunctions::equal(a, b); } + static void translate(ValueType& location, const KeyType& key, const MappedType& mapped) { - if (location.first == KeyStorageTraits::deletedValue()) - location.first = KeyStorageTraits::emptyValue(); - Assigner<KeyTraits::needsRef, KeyType, KeyStorageType, KeyTraits>::assign(key, location.first); - Assigner<MappedTraits::needsRef, MappedType, MappedStorageType, MappedTraits>::assign(mapped, location.second); + location.first = key; + location.second = mapped; } }; template<typename T, typename U, typename V, typename W, typename X> - inline void HashMap<T, U, V, W, X>::refAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::refAll(m_impl); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline void HashMap<T, U, V, W, X>::derefAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::derefAll(m_impl); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<T, U, V, W, X>::HashMap() - { - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<T, U, V, W, X>::HashMap(const HashMap& other) - : m_impl(other.m_impl) - { - refAll(); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<T, U, V, W, X>& HashMap<T, U, V, W, X>::operator=(const HashMap& other) - { - HashMap tmp(other); - swap(tmp); - return *this; - } - - 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 HashMap<T, U, V, W, X>::~HashMap() - { - derefAll(); - } - - 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(); @@ -247,27 +158,26 @@ namespace WTF { 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(*(const KeyStorageType*)&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(*(const KeyStorageType*)&key); + 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(*(const KeyStorageType*)&key); + return m_impl.contains(key); } 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, const MappedType& mapped) { - const bool canReplaceDeletedKey = !KeyTraits::needsDestruction || KeyStorageTraits::needsDestruction; - typedef HashMapTranslator<canReplaceDeletedKey, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> TranslatorType; + typedef HashMapTranslator<ValueType, ValueTraits, HashFunctions> TranslatorType; return m_impl.template add<KeyType, MappedType, TranslatorType>(key, mapped); } @@ -276,9 +186,10 @@ namespace WTF { HashMap<T, U, V, W, X>::set(const KeyType& key, const MappedType& mapped) { pair<iterator, bool> result = inlineAdd(key, mapped); - if (!result.second) + if (!result.second) { // add call above didn't change anything, so set the mapped value result.first->second = mapped; + } return result; } @@ -293,12 +204,10 @@ namespace WTF { typename HashMap<T, U, V, W, MappedTraits>::MappedType HashMap<T, U, V, W, MappedTraits>::get(const KeyType& key) const { - if (m_impl.isEmpty()) - return MappedTraits::emptyValue(); - ValueStorageType* entry = const_cast<HashTableType&>(m_impl).lookup(*(const KeyStorageType*)&key); + ValueType* entry = const_cast<HashTableType&>(m_impl).lookup(key); if (!entry) return MappedTraits::emptyValue(); - return ((ValueType *)entry)->second; + return entry->second; } template<typename T, typename U, typename V, typename W, typename X> @@ -307,7 +216,6 @@ namespace WTF { if (it.m_impl == m_impl.end()) return; m_impl.checkTableConsistency(); - RefCounter<ValueTraits, ValueStorageTraits>::deref(*it.m_impl); m_impl.removeWithoutEntryConsistencyCheck(it.m_impl); } @@ -320,7 +228,6 @@ namespace WTF { template<typename T, typename U, typename V, typename W, typename X> inline void HashMap<T, U, V, W, X>::clear() { - derefAll(); m_impl.clear(); } @@ -368,7 +275,7 @@ namespace WTF { typedef typename HashTableType::const_iterator iterator; iterator end = collection.end(); for (iterator it = collection.begin(); it != end; ++it) - delete *(MappedType*)&it->second; + delete it->second; } template<typename T, typename U, typename V, typename W, typename X> @@ -383,7 +290,7 @@ namespace WTF { typedef typename HashTableType::const_iterator iterator; iterator end = collection.end(); for (iterator it = collection.begin(); it != end; ++it) - delete *(KeyType*)&it->first; + delete it->first; } template<typename T, typename U, typename V, typename W, typename X> diff --git a/JavaScriptCore/wtf/HashSet.h b/JavaScriptCore/wtf/HashSet.h index f690956..da99f2c 100644 --- a/JavaScriptCore/wtf/HashSet.h +++ b/JavaScriptCore/wtf/HashSet.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * 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 @@ -26,36 +25,29 @@ namespace WTF { - template<typename T> 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 T> struct IdentityExtractor; + template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash, typename TraitsArg = HashTraits<ValueArg> > class HashSet { private: typedef HashArg HashFunctions; typedef TraitsArg ValueTraits; - typedef typename HashKeyStorageTraits<HashFunctions, ValueTraits>::Hash StorageHashFunctions; - - typedef typename HashKeyStorageTraits<HashFunctions, ValueTraits>::Traits StorageTraits; - typedef typename StorageTraits::TraitType StorageType; + public: + typedef typename ValueTraits::TraitType ValueType; - typedef HashTable<StorageType, StorageType, IdentityExtractor<StorageType>, - StorageHashFunctions, StorageTraits, StorageTraits> HashTableType; + private: + typedef HashTable<ValueType, ValueType, IdentityExtractor<ValueType>, + HashFunctions, ValueTraits, ValueTraits> HashTableType; public: - typedef typename ValueTraits::TraitType ValueType; typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator; typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator; - HashSet(); - HashSet(const HashSet&); - HashSet& operator=(const HashSet&); - ~HashSet(); - void swap(HashSet&); int size() const; @@ -71,13 +63,22 @@ namespace WTF { const_iterator find(const ValueType&) const; bool contains(const ValueType&) 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 + // 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; + + // 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&); - // a special version of add() that finds the object by hashing and comparing + // 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 should have the following methods: + // in the table. HashTranslator must have the following methods: // static unsigned hash(const T&); // static bool equal(const ValueType&, const T&); // static translate(ValueType&, const T&, unsigned hashCode); @@ -88,9 +89,6 @@ namespace WTF { void clear(); private: - void refAll(); - void derefAll(); - friend void deleteAllValues<>(const HashSet&); HashTableType m_impl; @@ -100,92 +98,16 @@ namespace WTF { static const T& extract(const T& t) { return t; } }; - template<bool canReplaceDeletedValue, typename ValueType, typename ValueTraits, typename StorageTraits, typename HashFunctions> - struct HashSetTranslator; - - template<typename ValueType, typename ValueTraits, typename StorageTraits, typename HashFunctions> - struct HashSetTranslator<true, ValueType, ValueTraits, StorageTraits, HashFunctions> { - typedef typename StorageTraits::TraitType StorageType; - static unsigned hash(const ValueType& key) { return HashFunctions::hash(key); } - static bool equal(const StorageType& a, const ValueType& b) { return HashFunctions::equal(*(const ValueType*)&a, b); } - static void translate(StorageType& location, const ValueType& key, const ValueType&) - { - Assigner<ValueTraits::needsRef, ValueType, StorageType, ValueTraits>::assign(key, location); - } - }; - - template<typename ValueType, typename ValueTraits, typename StorageTraits, typename HashFunctions> - struct HashSetTranslator<false, ValueType, ValueTraits, StorageTraits, HashFunctions> { - typedef typename StorageTraits::TraitType StorageType; - static unsigned hash(const ValueType& key) { return HashFunctions::hash(key); } - static bool equal(const StorageType& a, const ValueType& b) { return HashFunctions::equal(*(const ValueType*)&a, b); } - static void translate(StorageType& location, const ValueType& key, const ValueType&) - { - if (location == StorageTraits::deletedValue()) - location = StorageTraits::emptyValue(); - Assigner<ValueTraits::needsRef, ValueType, StorageType, ValueTraits>::assign(key, location); - } - }; - - template<bool canReplaceDeletedValue, typename ValueType, typename StorageTraits, typename T, typename Translator> - struct HashSetTranslatorAdapter; - - template<typename ValueType, typename StorageTraits, typename T, typename Translator> - struct HashSetTranslatorAdapter<true, ValueType, StorageTraits, T, Translator> { - typedef typename StorageTraits::TraitType StorageType; + template<typename ValueType, typename ValueTraits, typename T, typename Translator> + struct HashSetTranslatorAdapter { static unsigned hash(const T& key) { return Translator::hash(key); } - static bool equal(const StorageType& a, const T& b) { return Translator::equal(*(const ValueType*)&a, b); } - static void translate(StorageType& location, const T& key, const T&, unsigned hashCode) + static bool equal(const ValueType& a, const T& b) { return Translator::equal(a, b); } + static void translate(ValueType& location, const T& key, const T&, unsigned hashCode) { - Translator::translate(*(ValueType*)&location, key, hashCode); + Translator::translate(location, key, hashCode); } }; - template<typename ValueType, typename StorageTraits, typename T, typename Translator> - struct HashSetTranslatorAdapter<false, ValueType, StorageTraits, T, Translator> { - typedef typename StorageTraits::TraitType StorageType; - static unsigned hash(const T& key) { return Translator::hash(key); } - static bool equal(const StorageType& a, const T& b) { return Translator::equal(*(const ValueType*)&a, b); } - static void translate(StorageType& location, const T& key, const T&, unsigned hashCode) - { - if (location == StorageTraits::deletedValue()) - location = StorageTraits::emptyValue(); - Translator::translate(*(ValueType*)&location, key, hashCode); - } - }; - - template<typename T, typename U, typename V> - inline void HashSet<T, U, V>::refAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::refAll(m_impl); - } - - template<typename T, typename U, typename V> - inline void HashSet<T, U, V>::derefAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::derefAll(m_impl); - } - - template<typename T, typename U, typename V> - inline HashSet<T, U, V>::HashSet() - { - } - - template<typename T, typename U, typename V> - inline HashSet<T, U, V>::HashSet(const HashSet& other) - : m_impl(other.m_impl) - { - refAll(); - } - - template<typename T, typename U, typename V> - inline HashSet<T, U, V>& HashSet<T, U, V>::operator=(const HashSet& other) - { - HashSet tmp(other); - swap(tmp); - return *this; - } - template<typename T, typename U, typename V> inline void HashSet<T, U, V>::swap(HashSet& other) { @@ -193,12 +115,6 @@ namespace WTF { } template<typename T, typename U, typename V> - inline HashSet<T, U, V>::~HashSet() - { - derefAll(); - } - - template<typename T, typename U, typename V> inline int HashSet<T, U, V>::size() const { return m_impl.size(); @@ -243,27 +159,51 @@ namespace WTF { template<typename T, typename U, typename V> inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::find(const ValueType& value) { - return m_impl.find(*(const StorageType*)&value); + return m_impl.find(value); } template<typename T, typename U, typename V> inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::find(const ValueType& value) const { - return m_impl.find(*(const StorageType*)&value); + 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(*(const StorageType*)&value); + return m_impl.contains(value); + } + + template<typename Value, typename HashFunctions, typename Traits> + template<typename T, typename Translator> + typename HashSet<Value, HashFunctions, Traits>::iterator + inline HashSet<Value, HashFunctions, Traits>::find(const T& value) + { + typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, Translator> Adapter; + return m_impl.template find<T, Adapter>(value); + } + + template<typename Value, typename HashFunctions, typename Traits> + template<typename T, typename Translator> + typename HashSet<Value, HashFunctions, Traits>::const_iterator + inline HashSet<Value, HashFunctions, Traits>::find(const T& value) const + { + typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, Translator> Adapter; + return m_impl.template find<T, Adapter>(value); + } + + template<typename Value, typename HashFunctions, typename Traits> + template<typename T, typename Translator> + inline bool HashSet<Value, HashFunctions, Traits>::contains(const T& value) const + { + typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, Translator> Adapter; + return m_impl.template contains<T, Adapter>(value); } template<typename T, typename U, typename V> - pair<typename HashSet<T, U, V>::iterator, bool> HashSet<T, U, V>::add(const ValueType &value) + pair<typename HashSet<T, U, V>::iterator, bool> HashSet<T, U, V>::add(const ValueType& value) { - const bool canReplaceDeletedValue = !ValueTraits::needsDestruction || StorageTraits::needsDestruction; - typedef HashSetTranslator<canReplaceDeletedValue, ValueType, ValueTraits, StorageTraits, HashFunctions> Translator; - return m_impl.template add<ValueType, ValueType, Translator>(value, value); + return m_impl.add(value); } template<typename Value, typename HashFunctions, typename Traits> @@ -271,8 +211,7 @@ namespace WTF { pair<typename HashSet<Value, HashFunctions, Traits>::iterator, bool> HashSet<Value, HashFunctions, Traits>::add(const T& value) { - const bool canReplaceDeletedValue = !ValueTraits::needsDestruction || StorageTraits::needsDestruction; - typedef HashSetTranslatorAdapter<canReplaceDeletedValue, ValueType, StorageTraits, T, Translator> Adapter; + typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, Translator> Adapter; return m_impl.template addPassingHashCode<T, T, Adapter>(value, value); } @@ -282,7 +221,6 @@ namespace WTF { if (it.m_impl == m_impl.end()) return; m_impl.checkTableConsistency(); - RefCounter<ValueTraits, StorageTraits>::deref(*it.m_impl); m_impl.removeWithoutEntryConsistencyCheck(it.m_impl); } @@ -295,7 +233,6 @@ namespace WTF { template<typename T, typename U, typename V> inline void HashSet<T, U, V>::clear() { - derefAll(); m_impl.clear(); } @@ -305,7 +242,7 @@ namespace WTF { typedef typename HashTableType::const_iterator iterator; iterator end = collection.end(); for (iterator it = collection.begin(); it != end; ++it) - delete *(ValueType*)&*it; + delete *it; } template<typename T, typename U, typename V> diff --git a/JavaScriptCore/wtf/HashTable.cpp b/JavaScriptCore/wtf/HashTable.cpp index ba45aee..f1f2a4f 100644 --- a/JavaScriptCore/wtf/HashTable.cpp +++ b/JavaScriptCore/wtf/HashTable.cpp @@ -1,7 +1,5 @@ /* - This file is part of the KDE libraries - - Copyright (C) 2005 Apple Computer + 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 diff --git a/JavaScriptCore/wtf/HashTable.h b/JavaScriptCore/wtf/HashTable.h index 3b87490..4c7790a 100644 --- a/JavaScriptCore/wtf/HashTable.h +++ b/JavaScriptCore/wtf/HashTable.h @@ -1,7 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * This file is part of the KDE libraries - * Copyright (C) 2005, 2006 Apple Computer, Inc. + * 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 @@ -63,25 +61,26 @@ namespace WTF { template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> class HashTableConstIterator; -#if CHECK_HASHTABLE_ITERATORS 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>*); -#else + +#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: @@ -325,10 +324,11 @@ namespace WTF { void clear(); static bool isEmptyBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::emptyValue(); } - static bool isDeletedBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::deletedValue(); } + 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<Key, IdentityTranslatorType>(key); } + template<typename T, typename HashTranslator> ValueType* lookup(const T&); #if CHECK_HASHTABLE_CONSISTENCY void checkTableConsistency() const; @@ -343,11 +343,12 @@ namespace WTF { typedef pair<ValueType*, bool> LookupType; typedef pair<LookupType, unsigned> FullLookupType; - template<typename T, typename HashTranslator> ValueType* lookup(const T&); LookupType lookupForWriting(const Key& key) { return lookupForWriting<Key, IdentityTranslatorType>(key); }; template<typename T, typename HashTranslator> FullLookupType fullLookupForWriting(const T&); template<typename T, typename HashTranslator> LookupType lookupForWriting(const T&); + template<typename T, typename HashTranslator> void checkKey(const T&); + void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType*); void removeAndInvalidate(ValueType*); void remove(ValueType*); @@ -362,7 +363,7 @@ namespace WTF { void reinsert(ValueType&); static void initializeBucket(ValueType& bucket) { new (&bucket) ValueType(Traits::emptyValue()); } - static void deleteBucket(ValueType& bucket) { assignDeleted<ValueType, Traits>(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); } @@ -423,24 +424,47 @@ namespace WTF { return key; } +#if ASSERT_DISABLED + template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> template<typename T, typename HashTranslator> - inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key) + inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T&) { - ASSERT(m_table); -#if !ASSERT_DISABLED - if (HashFunctions::safeToCompareToEmptyOrDeleted) { - ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key)); - ASSERT(!HashTranslator::equal(KeyTraits::deletedValue(), key)); - } + } + +#else + + template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> + template<typename T, typename HashTranslator> + void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T& key) + { + if (!HashFunctions::safeToCompareToEmptyOrDeleted) + return; + ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key)); + ValueType deletedValue = Traits::emptyValue(); + deletedValue.~ValueType(); + Traits::constructDeletedValue(deletedValue); + ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue), key)); + new (&deletedValue) ValueType(Traits::emptyValue()); + } + #endif + template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> + template<typename T, typename HashTranslator> + inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key) + { + checkKey<T, 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 ++HashTableStats::numAccesses; int probeCount = 0; @@ -478,12 +502,7 @@ namespace WTF { inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookupForWriting(const T& key) { ASSERT(m_table); -#if !ASSERT_DISABLED - if (HashFunctions::safeToCompareToEmptyOrDeleted) { - ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key)); - ASSERT(!HashTranslator::equal(KeyTraits::deletedValue(), key)); - } -#endif + checkKey<T, HashTranslator>(key); int k = 0; ValueType* table = m_table; @@ -535,12 +554,7 @@ namespace WTF { inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::fullLookupForWriting(const T& key) { ASSERT(m_table); -#if !ASSERT_DISABLED - if (HashFunctions::safeToCompareToEmptyOrDeleted) { - ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key)); - ASSERT(!HashTranslator::equal(KeyTraits::deletedValue(), key)); - } -#endif + checkKey<T, HashTranslator>(key); int k = 0; ValueType* table = m_table; @@ -591,12 +605,7 @@ namespace WTF { template<typename T, typename Extra, typename HashTranslator> 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) { -#if !ASSERT_DISABLED - if (HashFunctions::safeToCompareToEmptyOrDeleted) { - ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key)); - ASSERT(!HashTranslator::equal(KeyTraits::deletedValue(), key)); - } -#endif + checkKey<T, HashTranslator>(key); invalidateIterators(); @@ -652,6 +661,7 @@ namespace WTF { } if (deletedEntry) { + initializeBucket(*deletedEntry); entry = deletedEntry; --m_deletedCount; } @@ -661,12 +671,14 @@ namespace WTF { ++m_keyCount; if (shouldExpand()) { - // FIXME: this makes an extra copy on expand. Probably not that bad since + // 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 + // follow a pivot entry and return the new position. KeyType enteredKey = Extractor::extract(*entry); expand(); - return std::make_pair(find(enteredKey), true); + pair<iterator, bool> p = std::make_pair(find(enteredKey), true); + ASSERT(p.first != end()); + return p; } checkTableConsistency(); @@ -678,6 +690,8 @@ namespace WTF { template<typename T, typename Extra, typename HashTranslator> 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<T, HashTranslator>(key); + invalidateIterators(); if (!m_table) @@ -687,25 +701,29 @@ namespace WTF { FullLookupType lookupResult = fullLookupForWriting<T, HashTranslator>(key); - ValueType *entry = lookupResult.first.first; + 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)) + 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 + // 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 + // follow a pivot entry and return the new position. KeyType enteredKey = Extractor::extract(*entry); expand(); - return std::make_pair(find(enteredKey), true); + pair<iterator, bool> p = std::make_pair(find(enteredKey), true); + ASSERT(p.first != end()); + return p; } checkTableConsistency(); @@ -723,7 +741,7 @@ namespace WTF { ++HashTableStats::numReinserts; #endif - Mover<ValueType, Traits::needsDestruction>::move(entry, *(lookupForWriting(Extractor::extract(entry)).first)); + Mover<ValueType, Traits::needsDestruction>::move(entry, *lookupForWriting(Extractor::extract(entry)).first); } template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> @@ -747,7 +765,7 @@ namespace WTF { if (!m_table) return end(); - ValueType* entry = const_cast<HashTable *>(this)->lookup<T, HashTranslator>(key); + ValueType* entry = const_cast<HashTable*>(this)->lookup<T, HashTranslator>(key); if (!entry) return end(); @@ -761,7 +779,7 @@ namespace WTF { if (!m_table) return false; - return const_cast<HashTable *>(this)->lookup<T, HashTranslator>(key); + return const_cast<HashTable*>(this)->lookup<T, HashTranslator>(key); } template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> @@ -821,12 +839,12 @@ namespace WTF { } template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> - Value *HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::allocateTable(int size) + 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))); + 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]); @@ -834,11 +852,14 @@ namespace WTF { } 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) + void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::deallocateTable(ValueType* table, int size) { - if (Traits::needsDestruction) - for (int i = 0; i < size; ++i) - table[i].~ValueType(); + if (Traits::needsDestruction) { + for (int i = 0; i < size; ++i) { + if (!isDeletedBucket(table[i])) + table[i].~ValueType(); + } + } fastFree(table); } @@ -862,7 +883,7 @@ namespace WTF { checkTableConsistencyExceptSize(); int oldTableSize = m_tableSize; - ValueType *oldTable = m_table; + ValueType* oldTable = m_table; #if DUMP_HASHTABLE_STATS if (oldTableSize != 0) @@ -919,7 +940,7 @@ namespace WTF { invalidateIterators(); other.invalidateIterators(); - ValueType *tmp_table = m_table; + ValueType* tmp_table = m_table; m_table = other.m_table; other.m_table = tmp_table; @@ -967,7 +988,7 @@ namespace WTF { int count = 0; int deletedCount = 0; for (int j = 0; j < m_tableSize; ++j) { - ValueType *entry = m_table + j; + ValueType* entry = m_table + j; if (isEmptyBucket(*entry)) continue; @@ -1115,137 +1136,6 @@ namespace WTF { return a.m_impl != b.m_impl; } - // reference count manager - - template<typename ValueTraits, typename ValueStorageTraits> struct NeedsRef { - static const bool value = ValueTraits::needsRef && !ValueStorageTraits::needsRef; - }; - template<typename FirstTraits, typename SecondTraits, typename ValueStorageTraits> - struct NeedsRef<PairBaseHashTraits<FirstTraits, SecondTraits>, ValueStorageTraits> { - typedef typename ValueStorageTraits::FirstTraits FirstStorageTraits; - typedef typename ValueStorageTraits::SecondTraits SecondStorageTraits; - static const bool firstNeedsRef = NeedsRef<FirstTraits, FirstStorageTraits>::value; - static const bool secondNeedsRef = NeedsRef<SecondTraits, SecondStorageTraits>::value; - static const bool value = firstNeedsRef || secondNeedsRef; - }; - - template<bool needsRef, typename ValueTraits, typename ValueStorageTraits> struct RefCounterBase; - - template<typename ValueTraits, typename ValueStorageTraits> - struct RefCounterBase<false, ValueTraits, ValueStorageTraits> { - typedef typename ValueStorageTraits::TraitType ValueStorageType; - static void ref(const ValueStorageType&) { } - static void deref(const ValueStorageType&) { } - }; - - template<typename ValueTraits, typename ValueStorageTraits> - struct RefCounterBase<true, ValueTraits, ValueStorageTraits> { - typedef typename ValueStorageTraits::TraitType ValueStorageType; - static void ref(const ValueStorageType& v) { ValueTraits::ref(v); } - static void deref(const ValueStorageType& v) { ValueTraits::deref(v); } - }; - - template<typename ValueTraits, typename ValueStorageTraits> struct RefCounter { - typedef typename ValueTraits::TraitType ValueType; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - static const bool needsRef = NeedsRef<ValueTraits, ValueStorageTraits>::value; - typedef RefCounterBase<needsRef, ValueTraits, ValueStorageTraits> Base; - static void ref(const ValueStorageType& v) { Base::ref(v); } - static void deref(const ValueStorageType& v) { Base::deref(v); } - }; - - template<typename FirstTraits, typename SecondTraits, typename ValueStorageTraits> - struct RefCounter<PairBaseHashTraits<FirstTraits, SecondTraits>, ValueStorageTraits> { - typedef typename FirstTraits::TraitType FirstType; - typedef typename SecondTraits::TraitType SecondType; - typedef typename ValueStorageTraits::FirstTraits FirstStorageTraits; - typedef typename ValueStorageTraits::SecondTraits SecondStorageTraits; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - static const bool firstNeedsRef = NeedsRef<FirstTraits, FirstStorageTraits>::value; - static const bool secondNeedsRef = NeedsRef<SecondTraits, SecondStorageTraits>::value; - typedef RefCounterBase<firstNeedsRef, FirstTraits, FirstStorageTraits> FirstBase; - typedef RefCounterBase<secondNeedsRef, SecondTraits, SecondStorageTraits> SecondBase; - static void ref(const ValueStorageType& v) { - FirstBase::ref(v.first); - SecondBase::ref(v.second); - } - static void deref(const ValueStorageType& v) { - FirstBase::deref(v.first); - SecondBase::deref(v.second); - } - }; - - template<bool needsRef, typename HashTableType, typename ValueTraits> struct HashTableRefCounterBase; - - template<typename HashTableType, typename ValueTraits> - struct HashTableRefCounterBase<false, HashTableType, ValueTraits> - { - static void refAll(HashTableType&) { } - static void derefAll(HashTableType&) { } - }; - - template<typename HashTableType, typename ValueTraits> - struct HashTableRefCounterBase<true, HashTableType, ValueTraits> - { - typedef typename HashTableType::iterator iterator; - typedef RefCounter<ValueTraits, typename HashTableType::ValueTraits> ValueRefCounter; - static void refAll(HashTableType&); - static void derefAll(HashTableType&); - }; - - template<typename HashTableType, typename ValueTraits> - void HashTableRefCounterBase<true, HashTableType, ValueTraits>::refAll(HashTableType& table) - { - iterator end = table.end(); - for (iterator it = table.begin(); it != end; ++it) - ValueRefCounter::ref(*it); - } - - template<typename HashTableType, typename ValueTraits> - void HashTableRefCounterBase<true, HashTableType, ValueTraits>::derefAll(HashTableType& table) - { - iterator end = table.end(); - for (iterator it = table.begin(); it != end; ++it) - ValueRefCounter::deref(*it); - } - - template<typename HashTableType, typename ValueTraits> struct HashTableRefCounter { - static const bool needsRef = NeedsRef<ValueTraits, typename HashTableType::ValueTraits>::value; - typedef HashTableRefCounterBase<needsRef, HashTableType, ValueTraits> Base; - static void refAll(HashTableType& table) { Base::refAll(table); } - static void derefAll(HashTableType& table) { Base::derefAll(table); } - }; - - // helper template for HashMap and HashSet. - template<bool needsRef, typename FromType, typename ToType, typename FromTraits> struct Assigner; - - template<typename FromType, typename ToType, typename FromTraits> struct Assigner<false, FromType, ToType, FromTraits> { - typedef union { - FromType m_from; - ToType m_to; - } UnionType; - - static void assign(const FromType& from, ToType& to) { reinterpret_cast<UnionType*>(&to)->m_from = from; } - }; - - template<typename FromType, typename ToType, typename FromTraits> struct Assigner<true, FromType, ToType, FromTraits> { - static void assign(const FromType& from, ToType& to) - { - ToType oldTo = to; - memcpy(&to, &from, sizeof(FromType)); - FromTraits::ref(to); - FromTraits::deref(oldTo); - } - }; - - template<typename FromType, typename FromTraits> struct Assigner<false, FromType, FromType, FromTraits> { - static void assign(const FromType& from, FromType& to) { to = from; } - }; - - template<typename FromType, typename FromTraits> struct Assigner<true, FromType, FromType, FromTraits> { - static void assign(const FromType& from, FromType& to) { to = from; } - }; - } // namespace WTF #include "HashIterators.h" diff --git a/JavaScriptCore/wtf/HashTraits.h b/JavaScriptCore/wtf/HashTraits.h index 5f35278..b3c0b7a 100644 --- a/JavaScriptCore/wtf/HashTraits.h +++ b/JavaScriptCore/wtf/HashTraits.h @@ -1,7 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * This file is part of the KDE libraries - * Copyright (C) 2005, 2006 Apple Computer, Inc. + * 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 @@ -47,6 +45,10 @@ namespace WTF { template<> struct IsInteger<long long> { static const bool value = true; }; template<> struct IsInteger<unsigned long long> { static const bool value = true; }; +#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED) + template<> struct IsInteger<wchar_t> { static const bool value = true; }; +#endif + COMPILE_ASSERT(IsInteger<bool>::value, WTF_IsInteger_bool_true); COMPILE_ASSERT(IsInteger<char>::value, WTF_IsInteger_char_true); COMPILE_ASSERT(IsInteger<signed char>::value, WTF_IsInteger_signed_char_true); @@ -60,6 +62,10 @@ namespace WTF { 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); @@ -69,183 +75,79 @@ namespace WTF { template<typename T> struct HashTraits; template<bool isInteger, typename T> struct GenericHashTraitsBase; - template<typename T> struct GenericHashTraitsBase<true, T> { - typedef T TraitType; - typedef HashTraits<typename IntTypes<sizeof(T)>::SignedType> StorageTraits; - static const bool emptyValueIsZero = true; - static const bool needsDestruction = false; - }; + template<typename T> struct GenericHashTraitsBase<false, T> { - typedef T TraitType; - typedef HashTraits<T> StorageTraits; static const bool emptyValueIsZero = false; static const bool needsDestruction = true; }; + // Default integer traits disallow both 0 and -1 as keys (max value instead of -1 for unsigned). + template<typename T> struct GenericHashTraitsBase<true, 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(); } - static const bool needsRef = false; }; template<typename T> struct HashTraits : GenericHashTraits<T> { }; - // signed integer traits may not be appropriate for all uses since they disallow 0 and -1 as keys - template<> struct HashTraits<signed char> : GenericHashTraits<int> { - static signed char deletedValue() { return -1; } - }; - template<> struct HashTraits<short> : GenericHashTraits<int> { - static short deletedValue() { return -1; } - }; - template<> struct HashTraits<int> : GenericHashTraits<int> { - static int deletedValue() { return -1; } - }; - template<> struct HashTraits<unsigned int> : GenericHashTraits<unsigned int> { - static unsigned int deletedValue() { return static_cast<unsigned int>(-1); } - }; - template<> struct HashTraits<long> : GenericHashTraits<long> { - static long deletedValue() { return -1; } - }; - template<> struct HashTraits<unsigned long> : GenericHashTraits<unsigned long> { - static unsigned long deletedValue() { return static_cast<unsigned long>(-1); } - }; - template<> struct HashTraits<long long> : GenericHashTraits<long long> { - static long long deletedValue() { return -1; } - }; - template<> struct HashTraits<unsigned long long> : GenericHashTraits<unsigned long long> { - static unsigned long long deletedValue() { return static_cast<unsigned long long>(-1); } - }; - - template<typename T> struct FloatHashTraits { - typedef T TraitType; - typedef HashTraits<T> StorageTraits; + template<typename T> struct FloatHashTraits : GenericHashTraits<T> { + static const bool needsDestruction = false; static T emptyValue() { return std::numeric_limits<T>::infinity(); } - static T deletedValue() { 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 const bool needsRef = false; - }; - template<> struct HashTraits<float> : FloatHashTraits<float> { - }; - template<> struct HashTraits<double> : FloatHashTraits<double> { + 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*> { - typedef HashTraits<typename IntTypes<sizeof(P*)>::SignedType> StorageTraits; static const bool emptyValueIsZero = true; static const bool needsDestruction = false; - static P* deletedValue() { return reinterpret_cast<P*>(-1); } + static void constructDeletedValue(P*& slot) { slot = reinterpret_cast<P*>(-1); } + static bool isDeletedValue(P* value) { return value == reinterpret_cast<P*>(-1); } }; template<typename P> struct HashTraits<RefPtr<P> > : GenericHashTraits<RefPtr<P> > { - typedef HashTraits<typename IntTypes<sizeof(P*)>::SignedType> StorageTraits; - typedef typename StorageTraits::TraitType StorageType; static const bool emptyValueIsZero = true; - static const bool needsRef = true; - - typedef union { - P* m_p; - StorageType m_s; - } UnionType; - - static void ref(const StorageType& s) - { - if (const P* p = reinterpret_cast<const UnionType*>(&s)->m_p) - const_cast<P*>(p)->ref(); - } - static void deref(const StorageType& s) - { - if (const P* p = reinterpret_cast<const UnionType*>(&s)->m_p) - const_cast<P*>(p)->deref(); - } - }; - - // template to set deleted values - - template<typename Traits> struct DeletedValueAssigner { - static void assignDeletedValue(typename Traits::TraitType& location) { location = Traits::deletedValue(); } + static void constructDeletedValue(RefPtr<P>& slot) { new (&slot) RefPtr<P>(HashTableDeletedValue); } + static bool isDeletedValue(const RefPtr<P>& value) { return value.isHashTableDeletedValue(); } }; - template<typename T, typename Traits> inline void assignDeleted(T& location) - { - DeletedValueAssigner<Traits>::assignDeletedValue(location); - } - // special traits for pairs, helpful for their use in HashMap implementation - template<typename FirstTraits, typename SecondTraits> struct PairHashTraits; - template<typename FirstTraitsArg, typename SecondTraitsArg> - struct PairBaseHashTraits : GenericHashTraits<pair<typename FirstTraitsArg::TraitType, typename SecondTraitsArg::TraitType> > { + 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; - typedef PairHashTraits<typename FirstTraits::StorageTraits, typename SecondTraits::StorageTraits> StorageTraits; - static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; - - static TraitType emptyValue() - { - return make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); - } - }; - - template<typename FirstTraits, typename SecondTraits> - struct PairHashTraits : PairBaseHashTraits<FirstTraits, SecondTraits> { - typedef pair<typename FirstTraits::TraitType, typename SecondTraits::TraitType> TraitType; + static TraitType emptyValue() { return make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; - static TraitType deletedValue() - { - return TraitType(FirstTraits::deletedValue(), SecondTraits::emptyValue()); - } - - static void assignDeletedValue(TraitType& location) - { - assignDeleted<typename FirstTraits::TraitType, FirstTraits>(location.first); - location.second = SecondTraits::emptyValue(); - } + 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> > { }; - template<typename FirstTraits, typename SecondTraits> - struct DeletedValueAssigner<PairHashTraits<FirstTraits, SecondTraits> > - { - static void assignDeletedValue(pair<typename FirstTraits::TraitType, typename SecondTraits::TraitType>& location) - { - PairHashTraits<FirstTraits, SecondTraits>::assignDeletedValue(location); - } - }; - - template<typename First, typename Second> - struct DeletedValueAssigner<HashTraits<pair<First, Second> > > - { - static void assignDeletedValue(pair<First, Second>& location) - { - HashTraits<pair<First, Second> >::assignDeletedValue(location); - } - }; - - // hash functions and traits that are equivalent (for code sharing) - - template<typename HashArg, typename TraitsArg> struct HashKeyStorageTraits { - typedef HashArg Hash; - typedef TraitsArg Traits; - }; - template<typename P> struct HashKeyStorageTraits<PtrHash<P*>, HashTraits<P*> > { - typedef typename IntTypes<sizeof(P*)>::SignedType IntType; - typedef IntHash<IntType> Hash; - typedef HashTraits<IntType> Traits; - }; - template<typename P> struct HashKeyStorageTraits<PtrHash<RefPtr<P> >, HashTraits<RefPtr<P> > > { - typedef typename IntTypes<sizeof(P*)>::SignedType IntType; - typedef IntHash<IntType> Hash; - typedef HashTraits<IntType> Traits; - }; - } // namespace WTF using WTF::HashTraits; diff --git a/JavaScriptCore/wtf/ListHashSet.h b/JavaScriptCore/wtf/ListHashSet.h index 3172943..2f75c33 100644 --- a/JavaScriptCore/wtf/ListHashSet.h +++ b/JavaScriptCore/wtf/ListHashSet.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * 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 @@ -34,7 +33,7 @@ namespace WTF { // 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, insertBefore, + // 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. @@ -91,10 +90,13 @@ namespace WTF { const_iterator find(const ValueType&) const; bool contains(const ValueType&) const; - // the return value is a pair of an interator to the new value's location, + // the return value 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(); @@ -102,6 +104,7 @@ namespace WTF { private: void unlinkAndDelete(Node*); void appendNode(Node*); + void insertNodeBefore(Node* beforeNode, Node* newNode); void deleteAllNodes(); iterator makeIterator(Node*); const_iterator makeConstIterator(Node*) const; @@ -309,7 +312,10 @@ namespace WTF { const_iterator& operator--() { ASSERT(m_position != m_set->m_head); - m_position = m_position->m_prev; + if (!m_position) + m_position = m_set->m_tail; + else + m_position = m_position->m_prev; return *this; } @@ -381,7 +387,6 @@ namespace WTF { std::swap(m_head, other.m_head); std::swap(m_tail, other.m_tail); m_allocator.swap(other.m_allocator); - return *this; } template<typename T, typename U> @@ -470,6 +475,23 @@ namespace WTF { } template<typename T, typename U> + pair<typename ListHashSet<T, U>::iterator, bool> ListHashSet<T, U>::insertBefore(iterator it, const ValueType& newValue) + { + typedef ListHashSetTranslator<ValueType, HashFunctions> Translator; + pair<typename ImplType::iterator, bool> result = m_impl.template add<ValueType, NodeAllocator*, Translator>(newValue, m_allocator.get()); + if (result.second) + insertNodeBefore(it.node(), *result.first); + return std::make_pair(makeIterator(*result.first), result.second); + + } + + template<typename T, typename U> + pair<typename ListHashSet<T, U>::iterator, bool> ListHashSet<T, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) + { + return insertBefore(find(beforeValue), newValue); + } + + template<typename T, typename U> inline void ListHashSet<T, U>::remove(iterator it) { if (it == end()) @@ -533,6 +555,22 @@ namespace WTF { } template<typename T, typename U> + void ListHashSet<T, 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, typename U> void ListHashSet<T, U>::deleteAllNodes() { if (!m_head) diff --git a/JavaScriptCore/wtf/ListRefPtr.h b/JavaScriptCore/wtf/ListRefPtr.h index 0f807b0..9f9a354 100644 --- a/JavaScriptCore/wtf/ListRefPtr.h +++ b/JavaScriptCore/wtf/ListRefPtr.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006 Apple Computer, Inc. + * 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 @@ -36,9 +35,10 @@ namespace WTF { // see comment in PassRefPtr.h for why this takes const reference template <typename U> ListRefPtr(const PassRefPtr<U>& o) : RefPtr<T>(o) {} - ~ListRefPtr() { + ~ListRefPtr() + { RefPtr<T> reaper = this->release(); - while (reaper && reaper->refcount() == 1) + while (reaper && reaper->hasOneRef()) reaper = reaper->releaseNext(); // implicitly protects reaper->next, then derefs reaper } diff --git a/JavaScriptCore/wtf/Locker.h b/JavaScriptCore/wtf/Locker.h new file mode 100644 index 0000000..9feec1f --- /dev/null +++ b/JavaScriptCore/wtf/Locker.h @@ -0,0 +1,47 @@ +/* + * 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 : Noncopyable { +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/JavaScriptCore/wtf/MainThread.cpp b/JavaScriptCore/wtf/MainThread.cpp new file mode 100644 index 0000000..6fe3021 --- /dev/null +++ b/JavaScriptCore/wtf/MainThread.cpp @@ -0,0 +1,141 @@ +/* + * 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 "Threading.h" +#include "Vector.h" + +namespace WTF { + +struct FunctionWithContext { + MainThreadFunction* function; + void* context; + ThreadCondition* syncFlag; + + FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0) + : function(function) + , context(context) + , syncFlag(syncFlag) + { + } +}; + +typedef Vector<FunctionWithContext> FunctionQueue; + +static bool callbacksPaused; // This global varialble is only accessed from main thread. + +Mutex& mainThreadFunctionQueueMutex() +{ + static Mutex staticMutex; + return staticMutex; +} + +static FunctionQueue& functionQueue() +{ + static FunctionQueue staticFunctionQueue; + return staticFunctionQueue; +} + +#if !PLATFORM(WIN) +void initializeMainThread() +{ + mainThreadFunctionQueueMutex(); +} +#endif + +void dispatchFunctionsFromMainThread() +{ + ASSERT(isMainThread()); + + if (callbacksPaused) + return; + + FunctionQueue queueCopy; + { + MutexLocker locker(mainThreadFunctionQueueMutex()); + queueCopy.swap(functionQueue()); + } + + for (unsigned i = 0; i < queueCopy.size(); ++i) { + FunctionWithContext& invocation = queueCopy[i]; + invocation.function(invocation.context); + if (invocation.syncFlag) + invocation.syncFlag->signal(); + } +} + +void callOnMainThread(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + { + MutexLocker locker(mainThreadFunctionQueueMutex()); + functionQueue().append(FunctionWithContext(function, context)); + } + + scheduleDispatchFunctionsOnMainThread(); +} + +void callOnMainThreadAndWait(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + if (isMainThread()) { + function(context); + return; + } + + ThreadCondition syncFlag; + Mutex conditionMutex; + + { + MutexLocker locker(mainThreadFunctionQueueMutex()); + functionQueue().append(FunctionWithContext(function, context, &syncFlag)); + conditionMutex.lock(); + } + + scheduleDispatchFunctionsOnMainThread(); + syncFlag.wait(conditionMutex); +} + +void setMainThreadCallbacksPaused(bool paused) +{ + ASSERT(isMainThread()); + + if (callbacksPaused == paused) + return; + + callbacksPaused = paused; + + if (!callbacksPaused) + scheduleDispatchFunctionsOnMainThread(); +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h new file mode 100644 index 0000000..953b986 --- /dev/null +++ b/JavaScriptCore/wtf/MainThread.h @@ -0,0 +1,57 @@ +/* + * 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 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 + +namespace WTF { + +class Mutex; + +typedef void MainThreadFunction(void*); + +void callOnMainThread(MainThreadFunction*, void* context); +void callOnMainThreadAndWait(MainThreadFunction*, void* context); + +void setMainThreadCallbacksPaused(bool paused); + +// Must be called from the main thread (Darwin is an exception to this rule). +void initializeMainThread(); + +// These functions are internal to the callOnMainThread implementation. +void dispatchFunctionsFromMainThread(); +void scheduleDispatchFunctionsOnMainThread(); +Mutex& mainThreadFunctionQueueMutex(); + +} // namespace WTF + +using WTF::callOnMainThread; +using WTF::setMainThreadCallbacksPaused; + +#endif // MainThread_h diff --git a/JavaScriptCore/wtf/MathExtras.h b/JavaScriptCore/wtf/MathExtras.h index 75991f0..cfe5468 100644 --- a/JavaScriptCore/wtf/MathExtras.h +++ b/JavaScriptCore/wtf/MathExtras.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 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 @@ -30,10 +30,15 @@ #include <stdlib.h> #include <time.h> -#if PLATFORM(SOLARIS) && COMPILER(GCC) +#if PLATFORM(SOLARIS) #include <ieeefp.h> #endif +#if PLATFORM(OPENBSD) +#include <sys/types.h> +#include <machine/ieee.h> +#endif + #if COMPILER(MSVC) #include <xmath.h> @@ -61,7 +66,16 @@ const double piOverFourDouble = M_PI_4; const float piOverFourFloat = static_cast<float>(M_PI_4); #endif -#if PLATFORM(SOLARIS) && COMPILER(GCC) +#if PLATFORM(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 PLATFORM(SOLARIS) #ifndef isfinite inline bool isfinite(double x) { return finite(x) && !isnand(x); } @@ -75,6 +89,17 @@ inline bool signbit(double x) { return x < 0.0; } // FIXME: Wrong for negative 0 #endif +#if PLATFORM(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) inline bool isinf(double num) { return !_finite(num) && !_isnan(num); } @@ -95,9 +120,9 @@ inline int isfinite(double x) { return _finite(x); } // Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values. inline double wtf_atan2(double x, double y) { - static double posInf = std::numeric_limits<double>::infinity(); - static double negInf = -std::numeric_limits<double>::infinity(); - static double nan = std::numeric_limits<double>::quiet_NaN(); + 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; diff --git a/JavaScriptCore/wtf/MessageQueue.h b/JavaScriptCore/wtf/MessageQueue.h new file mode 100644 index 0000000..481211d --- /dev/null +++ b/JavaScriptCore/wtf/MessageQueue.h @@ -0,0 +1,136 @@ +/* + * 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 MessageQueue_h +#define MessageQueue_h + +#include <wtf/Assertions.h> +#include <wtf/Deque.h> +#include <wtf/Noncopyable.h> +#include <wtf/Threading.h> + +namespace WTF { + + template<typename DataType> + class MessageQueue : Noncopyable { + public: + MessageQueue() : m_killed(false) {} + + void append(const DataType&); + void prepend(const DataType&); + bool waitForMessage(DataType&); + void kill(); + + bool tryGetMessage(DataType&); + bool killed() const; + + // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time. + bool isEmpty(); + + private: + mutable Mutex m_mutex; + ThreadCondition m_condition; + Deque<DataType> m_queue; + bool m_killed; + }; + + template<typename DataType> + inline void MessageQueue<DataType>::append(const DataType& message) + { + MutexLocker lock(m_mutex); + m_queue.append(message); + m_condition.signal(); + } + + template<typename DataType> + inline void MessageQueue<DataType>::prepend(const DataType& message) + { + MutexLocker lock(m_mutex); + m_queue.prepend(message); + m_condition.signal(); + } + + template<typename DataType> + inline bool MessageQueue<DataType>::waitForMessage(DataType& result) + { + MutexLocker lock(m_mutex); + + while (!m_killed && m_queue.isEmpty()) + m_condition.wait(m_mutex); + + if (m_killed) + return false; + + ASSERT(!m_queue.isEmpty()); + result = m_queue.first(); + m_queue.removeFirst(); + return true; + } + + template<typename DataType> + inline bool MessageQueue<DataType>::tryGetMessage(DataType& result) + { + MutexLocker lock(m_mutex); + if (m_killed) + return false; + if (m_queue.isEmpty()) + return false; + + result = m_queue.first(); + m_queue.removeFirst(); + return true; + } + + 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; + } +} + +using WTF::MessageQueue; + +#endif // MessageQueue_h diff --git a/JavaScriptCore/wtf/Noncopyable.h b/JavaScriptCore/wtf/Noncopyable.h index 358b0a7..f241c7c 100644 --- a/JavaScriptCore/wtf/Noncopyable.h +++ b/JavaScriptCore/wtf/Noncopyable.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2006 Apple Computer, Inc. * diff --git a/JavaScriptCore/wtf/NotFound.h b/JavaScriptCore/wtf/NotFound.h new file mode 100644 index 0000000..f0bb866 --- /dev/null +++ b/JavaScriptCore/wtf/NotFound.h @@ -0,0 +1,35 @@ +/* + * 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 + +#endif // NotFound_h diff --git a/JavaScriptCore/wtf/OwnArrayPtr.h b/JavaScriptCore/wtf/OwnArrayPtr.h index 2b6c7dc..344f813 100644 --- a/JavaScriptCore/wtf/OwnArrayPtr.h +++ b/JavaScriptCore/wtf/OwnArrayPtr.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2006 Apple Computer, Inc. * diff --git a/JavaScriptCore/wtf/OwnPtr.h b/JavaScriptCore/wtf/OwnPtr.h index b46969d..969950f 100644 --- a/JavaScriptCore/wtf/OwnPtr.h +++ b/JavaScriptCore/wtf/OwnPtr.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * diff --git a/JavaScriptCore/wtf/PassRefPtr.h b/JavaScriptCore/wtf/PassRefPtr.h index 25b9906..ca8f2cb 100644 --- a/JavaScriptCore/wtf/PassRefPtr.h +++ b/JavaScriptCore/wtf/PassRefPtr.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. * diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 655361b..80a7bf1 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -1,4 +1,3 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * @@ -21,7 +20,7 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WTF_Platform_h @@ -50,6 +49,14 @@ #define WTF_PLATFORM_WIN_OS 1 #endif +/* PLATFORM(WIN_CE) */ +/* Operating system level dependencies for Windows CE that should be used */ +/* regardless of operating environment */ +/* Note that for this platform PLATFORM(WIN_OS) is also defined. */ +#if defined(_WIN32_WCE) +#define WTF_PLATFORM_WIN_CE 1 +#endif + /* PLATFORM(FREEBSD) */ /* Operating system level dependencies for FreeBSD-like systems that */ /* should be used regardless of operating environment */ @@ -57,6 +64,13 @@ #define WTF_PLATFORM_FREEBSD 1 #endif +/* PLATFORM(OPENBSD) */ +/* Operating system level dependencies for OpenBSD systems that */ +/* should be used regardless of operating environment */ +#ifdef __OpenBSD__ +#define WTF_PLATFORM_OPENBSD 1 +#endif + /* PLATFORM(SOLARIS) */ /* Operating system level dependencies for Solaris that should be used */ /* regardless of operating environment */ @@ -79,11 +93,14 @@ /* Operating environments */ +/* PLATFORM(CHROMIUM) */ /* PLATFORM(QT) */ /* PLATFORM(GTK) */ /* PLATFORM(MAC) */ /* PLATFORM(WIN) */ -#if defined(BUILDING_QT__) +#if defined(BUILDING_CHROMIUM__) +#define WTF_PLATFORM_CHROMIUM 1 +#elif defined(BUILDING_QT__) #define WTF_PLATFORM_QT 1 /* PLATFORM(KDE) */ @@ -103,15 +120,21 @@ /* Graphics engines */ -/* PLATFORM(CG) */ -/* PLATFORM(CAIRO) */ +/* PLATFORM(CG) and PLATFORM(CI) */ #if PLATFORM(MAC) #define WTF_PLATFORM_CG 1 #define WTF_PLATFORM_CI 1 -#elif !PLATFORM(QT) && !PLATFORM(WX) -#define WTF_PLATFORM_CAIRO 1 #endif +/* PLATFORM(SKIA) */ +#if PLATFORM(CHROMIUM) +#define WTF_PLATFORM_SKIA 1 +#endif + +/* Makes PLATFORM(WIN) default to PLATFORM(CAIRO) */ +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(WX) +#define WTF_PLATFORM_CAIRO 1 +#endif #ifdef __S60__ // we are cross-compiling, it is not really windows @@ -123,6 +146,8 @@ #endif #ifdef ANDROID +#define WTF_PLATFORM_ANDROID 1 +#define WTF_PLATFORM_LINUX 1 //due to pthread code in collector.cpp, we need PLATFORM(DARWIN) //#undef WTF_PLATFORM_DARWIN #undef WTF_PLATFORM_MAC @@ -131,11 +156,17 @@ #undef WTF_PLATFORM_CG #undef WTF_PLATFORM_CI #undef WTF_PLATFORM_CAIRO +#define WTF_USE_PTHREADS 1 #define WTF_PLATFORM_SGL 1 #define WTF_PLATFORM_UNIX 1 #define USE_SYSTEM_MALLOC 1 +#define ENABLE_MAC_JAVA_BRIDGE 1 +#define LOG_DISABLED 1 +// Prevents Webkit from drawing the caret in textfields and textareas +// This prevents unnecessary invals. +#define ENABLE_TEXT_CARET 0 #endif // ANDROID /* CPU */ @@ -159,13 +190,14 @@ #define WTF_PLATFORM_BIG_ENDIAN 1 #endif +/* PLATFORM(ARM) */ #if defined(arm) \ || defined(__arm__) #define WTF_PLATFORM_ARM 1 #if defined(__ARMEB__) #define WTF_PLATFORM_BIG_ENDIAN 1 -#elif !defined(__ARM_EABI__) && !defined(__ARMEB__) -#if !defined(ANDROID) || !defined(__VFP_FP__) +#elif !defined(__ARM_EABI__) && !defined(__ARMEB__) && !defined(__VFP_FP__) +#if !defined(ANDROID) #define WTF_PLATFORM_MIDDLE_ENDIAN 1 #endif #endif @@ -190,6 +222,12 @@ #define WTF_PLATFORM_X86_64 1 #endif +/* PLATFORM(SPARC64) */ +#if defined(__sparc64__) +#define WTF_PLATFORM_SPARC64 1 +#define WTF_PLATFORM_BIG_ENDIAN 1 +#endif + /* Compiler */ /* COMPILER(MSVC) */ @@ -205,6 +243,11 @@ #define WTF_COMPILER_GCC 1 #endif +/* COMPILER(MINGW) */ +#if defined(MINGW) || defined(__MINGW32__) +#define WTF_COMPILER_MINGW 1 +#endif + /* COMPILER(BORLAND) */ /* not really fully supported - is this relevant any more? */ #if defined(__BORLANDC__) @@ -217,16 +260,17 @@ #define WTF_COMPILER_CYGWIN 1 #endif -/* multiple threads only supported on Mac for now */ -#if PLATFORM(MAC) || PLATFORM(WIN) -#define WTF_USE_MULTIPLE_THREADS 1 +#if (PLATFORM(MAC) || PLATFORM(WIN)) && !defined(ENABLE_JSC_MULTIPLE_THREADS) +#define ENABLE_JSC_MULTIPLE_THREADS 1 #endif -/* for Unicode, KDE uses Qt, everything else uses ICU */ +/* for Unicode, KDE uses Qt */ #if PLATFORM(KDE) || PLATFORM(QT) #define WTF_USE_QT4_UNICODE 1 #elif PLATFORM(SYMBIAN) #define WTF_USE_SYMBIAN_UNICODE 1 +#elif PLATFORM(GTK) +/* The GTK+ Unicode backend is configurable */ #else #define WTF_USE_ICU_UNICODE 1 #endif @@ -234,6 +278,16 @@ #if PLATFORM(MAC) #define WTF_PLATFORM_CF 1 #define WTF_USE_PTHREADS 1 +#if !defined(ENABLE_MAC_JAVA_BRIDGE) +#define ENABLE_MAC_JAVA_BRIDGE 1 +#endif +#if !defined(ENABLE_DASHBOARD_SUPPORT) +#define ENABLE_DASHBOARD_SUPPORT 1 +#endif +#define HAVE_READLINE 1 +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#define HAVE_DTRACE 1 +#endif #endif #if PLATFORM(WIN) @@ -245,10 +299,52 @@ #define WTF_USE_PTHREADS 1 #endif -#if PLATFORM(QT) -#define USE_SYSTEM_MALLOC 1 +#if PLATFORM(GTK) +#if HAVE(PTHREAD_H) +#define WTF_USE_PTHREADS 1 +#endif +#endif + +#if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM) +#define HAVE_ACCESSIBILITY 1 +#endif + +#if COMPILER(GCC) +#define HAVE_COMPUTED_GOTO 1 +#endif + +#if PLATFORM(DARWIN) + +#define HAVE_ERRNO_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 + +#elif PLATFORM(WIN_OS) + +#define HAVE_FLOAT_H 1 +#define HAVE_SYS_TIMEB_H 1 +#define HAVE_VIRTUALALLOC 1 + +#else + +/* FIXME: is this actually used or do other platforms generate their own config.h? */ + +#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 + #endif +/* ENABLE macro defaults */ + #if !defined(ENABLE_ICONDATABASE) #define ENABLE_ICONDATABASE 1 #endif @@ -257,8 +353,84 @@ #define ENABLE_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_DASHBOARD_SUPPORT) +#define ENABLE_DASHBOARD_SUPPORT 0 +#endif + +#if !defined(ENABLE_MAC_JAVA_BRIDGE) +#define ENABLE_MAC_JAVA_BRIDGE 0 +#endif + +#if !defined(ENABLE_NETSCAPE_PLUGIN_API) +#define ENABLE_NETSCAPE_PLUGIN_API 1 +#endif + +#if !defined(ENABLE_OPCODE_STATS) +#define ENABLE_OPCODE_STATS 0 +#endif + +#if !defined(ENABLE_CODEBLOCK_SAMPLING) +#define ENABLE_CODEBLOCK_SAMPLING 0 +#endif + +#if ENABLE(CODEBLOCK_SAMPLING) && !defined(ENABLE_OPCODE_SAMPLING) +#define ENABLE_OPCODE_SAMPLING 1 +#endif + +#if !defined(ENABLE_OPCODE_SAMPLING) +#define ENABLE_OPCODE_SAMPLING 0 +#endif + +#if !defined(ENABLE_GEOLOCATION) +#define ENABLE_GEOLOCATION 0 +#endif + +#if !defined(ENABLE_TEXT_CARET) +#define ENABLE_TEXT_CARET 1 +#endif + +// ANDROID addition: allow web archive to be disabled +#if !defined(ENABLE_ARCHIVE) +#define ENABLE_ARCHIVE 1 +#endif + +// CTI only supports x86 at the moment, and has only been tested on Mac and Windows. +#if !defined(ENABLE_CTI) && PLATFORM(X86) && (PLATFORM(MAC) || PLATFORM(WIN)) +#define ENABLE_CTI 1 +#endif + +// WREC only supports x86 at the moment, and has only been tested on Mac and Windows. +#if !defined(ENABLE_WREC) && ENABLE(CTI) && PLATFORM(X86) && (PLATFORM(MAC) || PLATFORM(WIN)) +#define ENABLE_WREC 1 +#endif + +#if ENABLE(CTI) || ENABLE(WREC) +#define ENABLE_MASM 1 +#endif + +#if !defined(ENABLE_PAN_SCROLLING) && (PLATFORM(WIN) || PLATFORM(CHROMIUM) || (PLATFORM(WX) && PLATFORM(WIN_OS))) +#define ENABLE_PAN_SCROLLING 1 +#endif + +/* Use the QtXmlStreamReader implementation for XMLTokenizer */ +#if PLATFORM(QT) +#if !ENABLE(XSLT) +#define WTF_USE_QXMLSTREAM 1 +#endif +#endif + +// Use "fastcall" calling convention on MSVC +#if COMPILER(MSVC) +#define WTF_USE_FAST_CALL_CTI_ARGUMENT 1 +#define WTF_USE_CTI_ARGUMENT 1 +#endif + #endif /* WTF_Platform_h */ diff --git a/JavaScriptCore/wtf/RefCounted.h b/JavaScriptCore/wtf/RefCounted.h index dc93b11..2dd5b2a 100644 --- a/JavaScriptCore/wtf/RefCounted.h +++ b/JavaScriptCore/wtf/RefCounted.h @@ -26,9 +26,30 @@ namespace WTF { -template<class T> class RefCounted : Noncopyable { +// 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 : Noncopyable { public: - RefCounted(int initialRefCount = 0) + void ref() + { + ASSERT(!m_deletionHasBegun); + ++m_refCount; + } + + bool hasOneRef() const + { + ASSERT(!m_deletionHasBegun); + return m_refCount == 1; + } + + int refCount() const + { + return m_refCount; + } + +protected: + RefCountedBase(int initialRefCount) : m_refCount(initialRefCount) #ifndef NDEBUG , m_deletionHasBegun(false) @@ -36,13 +57,10 @@ public: { } - void ref() - { - ASSERT(!m_deletionHasBegun); - ++m_refCount; - } + ~RefCountedBase() {} - void deref() + // Returns whether the pointer should be freed or not. + bool derefBase() { ASSERT(!m_deletionHasBegun); ASSERT(m_refCount > 0); @@ -50,20 +68,11 @@ public: #ifndef NDEBUG m_deletionHasBegun = true; #endif - delete static_cast<T*>(this); - } else - --m_refCount; - } + return true; + } - bool hasOneRef() - { - ASSERT(!m_deletionHasBegun); - return m_refCount == 1; - } - - int refCount() const - { - return m_refCount; + --m_refCount; + return false; } private: @@ -73,6 +82,24 @@ private: #endif }; + +template<class T> class RefCounted : public RefCountedBase { +public: + RefCounted(int initialRefCount = 1) + : RefCountedBase(initialRefCount) + { + } + + void deref() + { + if (derefBase()) + delete static_cast<T*>(this); + } + +protected: + ~RefCounted() {} +}; + } // namespace WTF using WTF::RefCounted; diff --git a/JavaScriptCore/wtf/RefCountedLeakCounter.cpp b/JavaScriptCore/wtf/RefCountedLeakCounter.cpp new file mode 100644 index 0000000..80922d3 --- /dev/null +++ b/JavaScriptCore/wtf/RefCountedLeakCounter.cpp @@ -0,0 +1,100 @@ +/* + * 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() +{ +#if ENABLE(JSC_MULTIPLE_THREADS) + atomicIncrement(&m_count); +#else + ++m_count; +#endif +} + +void RefCountedLeakCounter::decrement() +{ +#if ENABLE(JSC_MULTIPLE_THREADS) + atomicDecrement(&m_count); +#else + --m_count; +#endif +} + +#endif + +} // namespace WTF diff --git a/JavaScriptCore/wtf/RefCountedLeakCounter.h b/JavaScriptCore/wtf/RefCountedLeakCounter.h new file mode 100644 index 0000000..57cc283 --- /dev/null +++ b/JavaScriptCore/wtf/RefCountedLeakCounter.h @@ -0,0 +1,48 @@ +/* + * 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: + volatile int m_count; + const char* m_description; +#endif + }; + +} // namespace WTF + +#endif diff --git a/JavaScriptCore/wtf/RefPtr.h b/JavaScriptCore/wtf/RefPtr.h index d43a071..78bd257 100644 --- a/JavaScriptCore/wtf/RefPtr.h +++ b/JavaScriptCore/wtf/RefPtr.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * 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 @@ -31,9 +30,11 @@ namespace WTF { template <typename T> class PassRefPtr; + enum HashTableDeletedValueType { HashTableDeletedValue }; + template <typename T> class RefPtr { public: - RefPtr() : m_ptr(0) {} + RefPtr() : m_ptr(0) { } RefPtr(T* ptr) : m_ptr(ptr) { if (ptr) ptr->ref(); } RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) ptr->ref(); } // see comment in PassRefPtr.h for why this takes const reference @@ -42,6 +43,10 @@ namespace WTF { // Special constructor for cases where we overwrite an object in place. RefPtr(PlacementNewAdoptType) { } + // Hash table deleted values, which are only constructed and never copied or destroyed. + RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } + ~RefPtr() { if (T* ptr = m_ptr) ptr->deref(); } template <typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) ptr->ref(); } @@ -52,7 +57,7 @@ namespace WTF { 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; } + ALWAYS_INLINE T* operator->() const { return m_ptr; } bool operator!() const { return !m_ptr; } @@ -69,6 +74,8 @@ namespace WTF { void swap(RefPtr&); private: + static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + T* m_ptr; }; diff --git a/JavaScriptCore/wtf/RefPtrHashMap.h b/JavaScriptCore/wtf/RefPtrHashMap.h index 0515a24..1cbebb4 100644 --- a/JavaScriptCore/wtf/RefPtrHashMap.h +++ b/JavaScriptCore/wtf/RefPtrHashMap.h @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * 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 @@ -24,14 +23,30 @@ namespace WTF { // This specialization is a direct copy of HashMap, with overloaded functions // to allow for lookup by pointer instead of RefPtr, avoiding ref-count churn. - // FIXME: Is there a better way to do this that doesn't just copy HashMap? + // FIXME: Find a better way that doesn't require an entire copy of the HashMap template. + template<typename RawKeyType, typename ValueType, typename ValueTraits, typename HashFunctions> + struct RefPtrHashMapRawKeyTranslator { + typedef typename ValueType::first_type KeyType; + typedef typename ValueType::second_type MappedType; + typedef typename ValueTraits::FirstTraits KeyTraits; + typedef typename ValueTraits::SecondTraits MappedTraits; + + static unsigned hash(RawKeyType key) { return HashFunctions::hash(key); } + static bool equal(const KeyType& a, RawKeyType b) { return HashFunctions::equal(a, b); } + static void translate(ValueType& location, RawKeyType key, const MappedType& mapped) + { + location.first = key; + location.second = mapped; + } + }; + template<typename T, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> class HashMap<RefPtr<T>, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> { private: typedef KeyTraitsArg KeyTraits; typedef MappedTraitsArg MappedTraits; - typedef PairBaseHashTraits<KeyTraits, MappedTraits> ValueTraits; + typedef PairHashTraits<KeyTraits, MappedTraits> ValueTraits; public: typedef typename KeyTraits::TraitType KeyType; @@ -42,28 +57,16 @@ namespace WTF { private: typedef HashArg HashFunctions; - typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Hash StorageHashFunctions; - - typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Traits KeyStorageTraits; - typedef typename MappedTraits::StorageTraits MappedStorageTraits; - typedef PairHashTraits<KeyStorageTraits, MappedStorageTraits> ValueStorageTraits; + typedef HashTable<KeyType, ValueType, PairFirstExtractor<ValueType>, + HashFunctions, ValueTraits, KeyTraits> HashTableType; - typedef typename KeyStorageTraits::TraitType KeyStorageType; - typedef typename MappedStorageTraits::TraitType MappedStorageType; - typedef typename ValueStorageTraits::TraitType ValueStorageType; - - typedef HashTable<KeyStorageType, ValueStorageType, PairFirstExtractor<ValueStorageType>, - StorageHashFunctions, ValueStorageTraits, KeyStorageTraits> HashTableType; + typedef RefPtrHashMapRawKeyTranslator<RawKeyType, ValueType, ValueTraits, HashFunctions> + RawKeyTranslator; public: typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator; typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator; - HashMap(); - HashMap(const HashMap&); - HashMap& operator=(const HashMap&); - ~HashMap(); - void swap(HashMap&); int size() const; @@ -84,6 +87,7 @@ namespace WTF { bool contains(RawKeyType) const; MappedType get(const KeyType&) const; MappedType get(RawKeyType) const; + MappedType 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, @@ -108,57 +112,17 @@ namespace WTF { private: pair<iterator, bool> inlineAdd(const KeyType&, const MappedType&); pair<iterator, bool> inlineAdd(RawKeyType, const MappedType&); - void refAll(); - void derefAll(); HashTableType m_impl; }; template<typename T, typename U, typename V, typename W, typename X> - inline void HashMap<RefPtr<T>, U, V, W, X>::refAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::refAll(m_impl); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline void HashMap<RefPtr<T>, U, V, W, X>::derefAll() - { - HashTableRefCounter<HashTableType, ValueTraits>::derefAll(m_impl); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<RefPtr<T>, U, V, W, X>::HashMap() - { - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<RefPtr<T>, U, V, W, X>::HashMap(const HashMap& other) - : m_impl(other.m_impl) - { - refAll(); - } - - template<typename T, typename U, typename V, typename W, typename X> - inline HashMap<RefPtr<T>, U, V, W, X>& HashMap<RefPtr<T>, U, V, W, X>::operator=(const HashMap& other) - { - HashMap tmp(other); - swap(tmp); - return *this; - } - - 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 HashMap<RefPtr<T>, U, V, W, X>::~HashMap() - { - derefAll(); - } - - 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(); @@ -203,45 +167,44 @@ namespace WTF { 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(*(const KeyStorageType*)&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.find(*(const KeyStorageType*)&key); + return m_impl.template find<RawKeyType, RawKeyTranslator>(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(*(const KeyStorageType*)&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>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::find(RawKeyType key) const { - return m_impl.find(*(const KeyStorageType*)&key); + return m_impl.template find<RawKeyType, RawKeyTranslator>(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(*(const KeyStorageType*)&key); + 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.contains(*(const KeyStorageType*)&key); + return m_impl.template contains<RawKeyType, RawKeyTranslator>(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, const MappedType& mapped) { - const bool canReplaceDeletedKey = !KeyTraits::needsDestruction || KeyStorageTraits::needsDestruction; - typedef HashMapTranslator<canReplaceDeletedKey, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> TranslatorType; + typedef HashMapTranslator<ValueType, ValueTraits, HashFunctions> TranslatorType; return m_impl.template add<KeyType, MappedType, TranslatorType>(key, mapped); } @@ -249,7 +212,7 @@ namespace WTF { inline pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool> HashMap<RefPtr<T>, U, V, W, X>::inlineAdd(RawKeyType key, const MappedType& mapped) { - return inlineAdd(*(const KeyType*)&key, mapped); + return m_impl.template add<RawKeyType, MappedType, RawKeyTranslator>(key, mapped); } template<typename T, typename U, typename V, typename W, typename X> @@ -257,9 +220,10 @@ namespace WTF { HashMap<RefPtr<T>, U, V, W, X>::set(const KeyType& key, const MappedType& mapped) { pair<iterator, bool> result = inlineAdd(key, mapped); - if (!result.second) + if (!result.second) { // add call above didn't change anything, so set the mapped value result.first->second = mapped; + } return result; } @@ -268,9 +232,10 @@ namespace WTF { HashMap<RefPtr<T>, U, V, W, X>::set(RawKeyType key, const MappedType& mapped) { pair<iterator, bool> result = inlineAdd(key, mapped); - if (!result.second) + if (!result.second) { // add call above didn't change anything, so set the mapped value result.first->second = mapped; + } return result; } @@ -292,24 +257,27 @@ namespace WTF { typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(const KeyType& key) const { - if (m_impl.isEmpty()) - return MappedTraits::emptyValue(); - ValueStorageType* entry = const_cast<HashTableType&>(m_impl).lookup(*(const KeyStorageType*)&key); + ValueType* entry = const_cast<HashTableType&>(m_impl).lookup(key); if (!entry) return MappedTraits::emptyValue(); - return ((ValueType *)entry)->second; + return entry->second; } template<typename T, typename U, typename V, typename W, typename MappedTraits> typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType - HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(RawKeyType key) const + inline HashMap<RefPtr<T>, U, V, W, MappedTraits>::inlineGet(RawKeyType key) const { - if (m_impl.isEmpty()) - return MappedTraits::emptyValue(); - ValueStorageType* entry = const_cast<HashTableType&>(m_impl).lookup(*(const KeyStorageType*)&key); + ValueType* entry = const_cast<HashTableType&>(m_impl).template lookup<RawKeyType, RawKeyTranslator>(key); if (!entry) return MappedTraits::emptyValue(); - return ((ValueType *)entry)->second; + return entry->second; + } + + template<typename T, typename U, typename V, typename W, typename MappedTraits> + typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType + 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> @@ -318,7 +286,6 @@ namespace WTF { if (it.m_impl == m_impl.end()) return; m_impl.checkTableConsistency(); - RefCounter<ValueTraits, ValueStorageTraits>::deref(*it.m_impl); m_impl.removeWithoutEntryConsistencyCheck(it.m_impl); } @@ -337,7 +304,6 @@ namespace WTF { template<typename T, typename U, typename V, typename W, typename X> inline void HashMap<RefPtr<T>, U, V, W, X>::clear() { - derefAll(); m_impl.clear(); } diff --git a/JavaScriptCore/wtf/RetainPtr.h b/JavaScriptCore/wtf/RetainPtr.h index 71260eb..2d73603 100644 --- a/JavaScriptCore/wtf/RetainPtr.h +++ b/JavaScriptCore/wtf/RetainPtr.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * This file is part of the KDE libraries * Copyright (C) 2005, 2006 Apple Computer, Inc. diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index ca1c20c..881b066 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,27 +26,58 @@ #ifndef WTF_StringExtras_h #define WTF_StringExtras_h -#include <stdio.h> #include <stdarg.h> +#include <stdio.h> #if COMPILER(MSVC) -inline int snprintf(char *str, size_t size, const char* format, ...) +inline int snprintf(char* buffer, size_t count, const char* format, ...) { int result; va_list args; va_start(args, format); - result = _vsnprintf(str, size, format, args); + result = _vsnprintf(buffer, count, format, args); va_end(args); return result; } -#if COMPILER(MSVC7) -// MSVC8 and above define this function -#define vsnprintf snprintf +#if COMPILER(MSVC7) || PLATFORM(WIN_CE) + +inline int vsnprintf(char* buffer, size_t count, const char* format, va_list args) +{ + return _vsnprintf(buffer, count, format, args); +} + #endif -inline int strncasecmp(const char* s1, const char* s2, size_t len) { return strnicmp(s1, s2, len); } +#if PLATFORM(WIN_CE) + +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 diff --git a/JavaScriptCore/wtf/TCSpinLock.h b/JavaScriptCore/wtf/TCSpinLock.h index 2bfd090..3c6ac11 100644 --- a/JavaScriptCore/wtf/TCSpinLock.h +++ b/JavaScriptCore/wtf/TCSpinLock.h @@ -48,7 +48,7 @@ #endif #include <stdlib.h> /* for abort() */ -#if COMPILER(MSVC) +#if PLATFORM(WIN_OS) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -104,7 +104,7 @@ struct TCMalloc_SpinLock { ("isync\n\t" "eieio\n\t" "stw %1, %0" -#if PLATFORM(DARWIN) +#if PLATFORM(DARWIN) || PLATFORM(PPC) : "=o" (lockword_) #else : "=m" (lockword_) @@ -179,7 +179,7 @@ static void TCMalloc_SlowLock(volatile unsigned int* lockword) { // from taking 30 seconds to 16 seconds. // Sleep for a few milliseconds -#if COMPILER(MSVC) +#if PLATFORM(WIN_OS) Sleep(2); #else struct timespec tm; diff --git a/JavaScriptCore/wtf/TCSystemAlloc.cpp b/JavaScriptCore/wtf/TCSystemAlloc.cpp index 73f9341..bd6eb33 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.cpp +++ b/JavaScriptCore/wtf/TCSystemAlloc.cpp @@ -224,7 +224,7 @@ static void* TryVirtualAlloc(size_t size, size_t *actual_size, size_t alignment) } void* result = VirtualAlloc(NULL, size + extra, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, - PAGE_READWRITE); + PAGE_EXECUTE_READWRITE); if (result == NULL) { VirtualAlloc_failure = true; @@ -428,3 +428,11 @@ void TCMalloc_SystemRelease(void* start, size_t length) return; #endif } + +#if HAVE(VIRTUALALLOC) +void TCMalloc_SystemCommit(void* start, size_t length) +{ + UNUSED_PARAM(start); + UNUSED_PARAM(length); +} +#endif diff --git a/JavaScriptCore/wtf/TCSystemAlloc.h b/JavaScriptCore/wtf/TCSystemAlloc.h index d9d4a2b..d82e860 100644 --- a/JavaScriptCore/wtf/TCSystemAlloc.h +++ b/JavaScriptCore/wtf/TCSystemAlloc.h @@ -62,4 +62,10 @@ extern void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes, // be released, partial pages will not.) extern void TCMalloc_SystemRelease(void* start, size_t length); +#if HAVE(VIRTUALALLOC) +extern void TCMalloc_SystemCommit(void* start, size_t length); +#else +inline void TCMalloc_SystemCommit(void*, size_t) { } +#endif + #endif /* TCMALLOC_SYSTEM_ALLOC_H__ */ diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h new file mode 100644 index 0000000..87709a1 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -0,0 +1,134 @@ +/* + * 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_ThreadSpecific_h +#define WTF_ThreadSpecific_h + +#include <wtf/Noncopyable.h> + +#if USE(PTHREADS) || PLATFORM(WIN) +// Windows currently doesn't use pthreads for basic threading, but implementing destructor functions is easier +// with pthreads, so we use it here. +#include <pthread.h> +#endif + +namespace WTF { + +template<typename T> class ThreadSpecific : Noncopyable { +public: + ThreadSpecific(); + T* operator->(); + operator T*(); + T& operator*(); + ~ThreadSpecific(); + +private: + T* get(); + void set(T*); + void static destroy(void* ptr); + +#if USE(PTHREADS) || PLATFORM(WIN) + struct Data : Noncopyable { + Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} + + T* value; + ThreadSpecific<T>* owner; + }; + + pthread_key_t m_key; +#endif +}; + +#if USE(PTHREADS) || PLATFORM(WIN) +template<typename T> +inline ThreadSpecific<T>::ThreadSpecific() +{ + int error = pthread_key_create(&m_key, destroy); + if (error) + CRASH(); +} + +template<typename T> +inline ThreadSpecific<T>::~ThreadSpecific() +{ + pthread_key_delete(m_key); // Does not invoke destructor functions. +} + +template<typename T> +inline T* ThreadSpecific<T>::get() +{ + Data* data = static_cast<Data*>(pthread_getspecific(m_key)); + 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)); +} + +template<typename T> +inline void ThreadSpecific<T>::destroy(void* ptr) +{ + Data* data = static_cast<Data*>(ptr); + pthread_setspecific(data->owner->m_key, 0); + delete data->value; + delete data; +} + +#else +#error ThreadSpecific is not implemented for this platform. +#endif + +template<typename T> +inline ThreadSpecific<T>::operator T*() +{ + T* ptr = static_cast<T*>(get()); + if (!ptr) { + ptr = new T(); + set(ptr); + } + 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/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h new file mode 100644 index 0000000..b464da3 --- /dev/null +++ b/JavaScriptCore/wtf/Threading.h @@ -0,0 +1,284 @@ +/* + * 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 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 <wtf/Assertions.h> +#include <wtf/Locker.h> +#include <wtf/Noncopyable.h> + +#if PLATFORM(WIN_OS) +#include <windows.h> +#elif PLATFORM(DARWIN) +#include <libkern/OSAtomic.h> +#elif defined ANDROID +#include "cutils/atomic.h" +#elif COMPILER(GCC) +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) +#include <ext/atomicity.h> +#else +#include <bits/atomicity.h> +#endif +#endif + +#if USE(PTHREADS) +#include <pthread.h> +#elif PLATFORM(GTK) +#include <wtf/GOwnPtr.h> +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +#endif + +#if PLATFORM(QT) +#include <qglobal.h> +QT_BEGIN_NAMESPACE +class QMutex; +class QWaitCondition; +QT_END_NAMESPACE +#endif + +#include <stdint.h> + +// 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); + +// Returns 0 if thread creation failed +ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); + +ThreadIdentifier currentThread(); +bool isMainThread(); +int waitForThreadCompletion(ThreadIdentifier, void**); +void detachThread(ThreadIdentifier); + +#if USE(PTHREADS) +typedef pthread_mutex_t PlatformMutex; +typedef pthread_cond_t PlatformCondition; +#elif PLATFORM(GTK) +typedef GOwnPtr<GMutex> PlatformMutex; +typedef GOwnPtr<GCond> PlatformCondition; +#elif PLATFORM(QT) +typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; +typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; +#elif PLATFORM(WIN_OS) +struct PlatformMutex { + CRITICAL_SECTION m_internalMutex; + size_t m_recursionCount; +}; +struct PlatformCondition { + size_t m_timedOut; + size_t m_blocked; + size_t m_waitingForRemoval; + HANDLE m_gate; + HANDLE m_queue; + HANDLE m_mutex; +}; +#else +typedef void* PlatformMutex; +typedef void* PlatformCondition; +#endif + +class Mutex : Noncopyable { +public: + Mutex(); + ~Mutex(); + + void lock(); + bool tryLock(); + void unlock(); + +public: + PlatformMutex& impl() { return m_mutex; } +private: + PlatformMutex m_mutex; +}; + +typedef Locker<Mutex> MutexLocker; + +class ThreadCondition : Noncopyable { +public: + ThreadCondition(); + ~ThreadCondition(); + + void wait(Mutex& mutex); + // Returns true if the condition was signaled before the timeout, false if the timeout was reached + bool timedWait(Mutex&, double interval); + void signal(); + void broadcast(); + +private: + PlatformCondition m_condition; +}; + +#if PLATFORM(WIN_OS) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +#if COMPILER(MINGW) || COMPILER(MSVC7) +inline void atomicIncrement(int* addend) { InterlockedIncrement(reinterpret_cast<long*>(addend)); } +inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } +#else +inline void atomicIncrement(int volatile* addend) { InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } +#endif + +#elif PLATFORM(DARWIN) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline void atomicIncrement(int volatile* addend) { OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } + +#elif defined ANDROID + +inline void atomicIncrement(int volatile* addend) { android_atomic_inc(addend); } +inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } + +#elif COMPILER(GCC) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline void atomicIncrement(int volatile* addend) { __gnu_cxx::__atomic_add(addend, 1); } +inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } + +#endif + +template<class T> class ThreadSafeShared : Noncopyable { +public: + ThreadSafeShared(int initialRefCount = 1) + : m_refCount(initialRefCount) + { + } + + void ref() + { +#if USE(LOCKFREE_THREADSAFESHARED) + atomicIncrement(&m_refCount); +#else + MutexLocker locker(m_mutex); + ++m_refCount; +#endif + } + + void deref() + { +#if USE(LOCKFREE_THREADSAFESHARED) + if (atomicDecrement(&m_refCount) <= 0) +#else + { + MutexLocker locker(m_mutex); + --m_refCount; + } + if (m_refCount <= 0) +#endif + delete static_cast<T*>(this); + } + + bool hasOneRef() + { + return refCount() == 1; + } + + int refCount() const + { +#if !USE(LOCKFREE_THREADSAFESHARED) + MutexLocker locker(m_mutex); +#endif + return static_cast<int const volatile &>(m_refCount); + } + +private: + int m_refCount; +#if !USE(LOCKFREE_THREADSAFESHARED) + mutable Mutex m_mutex; +#endif +}; + +// 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(); + +#if !PLATFORM(WIN_OS) || PLATFORM(WX) +extern Mutex* atomicallyInitializedStaticMutex; +inline void lockAtomicallyInitializedStaticMutex() { atomicallyInitializedStaticMutex->lock(); } +inline void unlockAtomicallyInitializedStaticMutex() { atomicallyInitializedStaticMutex->unlock(); } +#else +void lockAtomicallyInitializedStaticMutex(); +void unlockAtomicallyInitializedStaticMutex(); +#endif + +} // namespace WTF + +using WTF::Mutex; +using WTF::MutexLocker; +using WTF::ThreadCondition; +using WTF::ThreadIdentifier; +using WTF::ThreadSafeShared; + +using WTF::createThread; +using WTF::currentThread; +using WTF::isMainThread; +using WTF::detachThread; +using WTF::waitForThreadCompletion; + +#endif // Threading_h diff --git a/JavaScriptCore/wtf/ThreadingGtk.cpp b/JavaScriptCore/wtf/ThreadingGtk.cpp new file mode 100644 index 0000000..53fd1fe --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingGtk.cpp @@ -0,0 +1,229 @@ +/* + * 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 "Threading.h" + +#if !USE(PTHREADS) + +#include "HashMap.h" +#include "MainThread.h" +#include "MathExtras.h" + +#include <glib.h> + +namespace WTF { + +Mutex* atomicallyInitializedStaticMutex; + +static ThreadIdentifier mainThreadIdentifier; + +static Mutex& threadMapMutex() +{ + static Mutex mutex; + return mutex; +} + +void initializeThreading() +{ + if (!g_thread_supported()) + g_thread_init(NULL); + ASSERT(g_thread_supported()); + + if (!atomicallyInitializedStaticMutex) { + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + wtf_random_init(); + mainThreadIdentifier = currentThread(); + initializeMainThread(); + } +} + +static HashMap<ThreadIdentifier, GThread*>& threadMap() +{ + static HashMap<ThreadIdentifier, GThread*> map; + return map; +} + +static ThreadIdentifier establishIdentifierForThread(GThread*& thread) +{ + MutexLocker locker(threadMapMutex()); + + static ThreadIdentifier identifierCount = 1; + + threadMap().add(identifierCount, thread); + + return identifierCount++; +} + +static ThreadIdentifier identifierByGthreadHandle(GThread*& thread) +{ + MutexLocker locker(threadMapMutex()); + + HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin(); + for (; i != threadMap().end(); ++i) { + if (i->second == thread) + return i->first; + } + + return 0; +} + +static GThread* threadForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + return threadMap().get(id); +} + +static void clearThreadForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + ASSERT(threadMap().contains(id)); + + threadMap().remove(id); +} + +ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char*) +{ + GThread* thread; + if (!(thread = g_thread_create(entryPoint, data, TRUE, 0))) { + LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data); + return 0; + } + + ThreadIdentifier threadID = establishIdentifierForThread(thread); + return threadID; +} + +int waitForThreadCompletion(ThreadIdentifier threadID, void** result) +{ + ASSERT(threadID); + + GThread* thread = threadForIdentifier(threadID); + + *result = g_thread_join(thread); + + clearThreadForIdentifier(threadID); + return 0; +} + +void detachThread(ThreadIdentifier) +{ +} + +ThreadIdentifier currentThread() +{ + GThread* currentThread = g_thread_self(); + if (ThreadIdentifier id = identifierByGthreadHandle(currentThread)) + return id; + return establishIdentifierForThread(currentThread); +} + +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} + +Mutex::Mutex() + : m_mutex(g_mutex_new()) +{ +} + +Mutex::~Mutex() +{ +} + +void Mutex::lock() +{ + g_mutex_lock(m_mutex.get()); +} + +bool Mutex::tryLock() +{ + return g_mutex_trylock(m_mutex.get()); +} + +void Mutex::unlock() +{ + g_mutex_unlock(m_mutex.get()); +} + +ThreadCondition::ThreadCondition() + : m_condition(g_cond_new()) +{ +} + +ThreadCondition::~ThreadCondition() +{ +} + +void ThreadCondition::wait(Mutex& mutex) +{ + g_cond_wait(m_condition.get(), mutex.impl().get()); +} + +bool ThreadCondition::timedWait(Mutex& mutex, double interval) +{ + if (interval < 0.0) { + wait(mutex); + return true; + } + + int intervalSeconds = static_cast<int>(interval); + int intervalMicroseconds = static_cast<int>((interval - intervalSeconds) * 1000000.0); + + GTimeVal targetTime; + g_get_current_time(&targetTime); + + targetTime.tv_sec += intervalSeconds; + targetTime.tv_usec += intervalMicroseconds; + if (targetTime.tv_usec > 1000000) { + targetTime.tv_usec -= 1000000; + targetTime.tv_sec++; + } + + return g_cond_timed_wait(m_condition.get(), mutex.impl().get(), &targetTime); +} + +void ThreadCondition::signal() +{ + g_cond_signal(m_condition.get()); +} + +void ThreadCondition::broadcast() +{ + g_cond_broadcast(m_condition.get()); +} + + +} + +#endif // !USE(PTHREADS) diff --git a/JavaScriptCore/wtf/ThreadingNone.cpp b/JavaScriptCore/wtf/ThreadingNone.cpp new file mode 100644 index 0000000..c17b3b2 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingNone.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 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. + */ +#include "config.h" +#include "Threading.h" + +namespace WTF { + +Mutex* atomicallyInitializedStaticMutex; + +void initializeThreading() {} +ThreadIdentifier createThread(ThreadFunction, void*, const char*) { return 0; } +int waitForThreadCompletion(ThreadIdentifier, void**) { return 0; } +void detachThread(ThreadIdentifier) { } +ThreadIdentifier currentThread() { return 0; } +bool isMainThread() { return false; } + +Mutex::Mutex() {} +Mutex::~Mutex() {} +void Mutex::lock() {} +bool Mutex::tryLock() { return false; } +void Mutex::unlock() {}; + +ThreadCondition::ThreadCondition() {} +ThreadCondition::~ThreadCondition() {} +void ThreadCondition::wait(Mutex& mutex) {} +bool ThreadCondition::timedWait(Mutex& mutex, double interval) { return false; } +void ThreadCondition::signal() {} +void ThreadCondition::broadcast() {} + +} // namespace WebCore diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp new file mode 100644 index 0000000..d17a03d --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2007 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. + */ +#include "config.h" +#include "Threading.h" + +#if USE(PTHREADS) + +#include "HashMap.h" +#include "MainThread.h" +#include "MathExtras.h" + +#include <errno.h> +#include <sys/time.h> + +namespace WTF { + +Mutex* atomicallyInitializedStaticMutex; + +#if !PLATFORM(DARWIN) +static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread. +#endif + +static Mutex& threadMapMutex() +{ + static Mutex mutex; + return mutex; +} + +void initializeThreading() +{ + if (!atomicallyInitializedStaticMutex) { + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + wtf_random_init(); +#if !PLATFORM(DARWIN) + mainThreadIdentifier = currentThread(); +#endif + initializeMainThread(); + } +} + +static HashMap<ThreadIdentifier, pthread_t>& threadMap() +{ + static HashMap<ThreadIdentifier, pthread_t> map; + return map; +} + +static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle) +{ + MutexLocker locker(threadMapMutex()); + + static ThreadIdentifier identifierCount = 1; + + threadMap().add(identifierCount, pthreadHandle); + + return identifierCount++; +} + +static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle) +{ + MutexLocker locker(threadMapMutex()); + + HashMap<ThreadIdentifier, pthread_t>::iterator i = threadMap().begin(); + for (; i != threadMap().end(); ++i) { + if (pthread_equal(i->second, pthreadHandle)) + return i->first; + } + + return 0; +} + +static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + return threadMap().get(id); +} + +static void clearPthreadHandleForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + ASSERT(threadMap().contains(id)); + + threadMap().remove(id); +} + +ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char*) +{ + pthread_t threadHandle; + if (pthread_create(&threadHandle, NULL, entryPoint, data)) { + LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data); + return 0; + } + + ThreadIdentifier threadID = establishIdentifierForPthreadHandle(threadHandle); + return threadID; +} + +#if PLATFORM(MAC) +// This function is deprecated but needs to be kept around for backward +// compatibility. Use the 3-argument version of createThread above instead. +ThreadIdentifier createThread(ThreadFunction entryPoint, void* data) +{ + return createThread(entryPoint, data, 0); +} +#endif + +int waitForThreadCompletion(ThreadIdentifier threadID, void** result) +{ + ASSERT(threadID); + + pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID); + + int joinResult = pthread_join(pthreadHandle, result); + if (joinResult == EDEADLK) + LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID); + + clearPthreadHandleForIdentifier(threadID); + return joinResult; +} + +void detachThread(ThreadIdentifier threadID) +{ + ASSERT(threadID); + + pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID); + + pthread_detach(pthreadHandle); + + clearPthreadHandleForIdentifier(threadID); +} + +ThreadIdentifier currentThread() +{ + pthread_t currentThread = pthread_self(); + if (ThreadIdentifier id = identifierByPthreadHandle(currentThread)) + return id; + return establishIdentifierForPthreadHandle(currentThread); +} + +bool isMainThread() +{ +#if PLATFORM(DARWIN) + return pthread_main_np(); +#else + return currentThread() == mainThreadIdentifier; +#endif +} + +Mutex::Mutex() +{ + pthread_mutex_init(&m_mutex, NULL); +} + +Mutex::~Mutex() +{ + pthread_mutex_destroy(&m_mutex); +} + +void Mutex::lock() +{ + if (pthread_mutex_lock(&m_mutex) != 0) + ASSERT(false); +} + +bool Mutex::tryLock() +{ + int result = pthread_mutex_trylock(&m_mutex); + + if (result == 0) + return true; + else if (result == EBUSY) + return false; + + ASSERT(false); + return false; +} + +void Mutex::unlock() +{ + if (pthread_mutex_unlock(&m_mutex) != 0) + ASSERT(false); +} + +ThreadCondition::ThreadCondition() +{ + pthread_cond_init(&m_condition, NULL); +} + +ThreadCondition::~ThreadCondition() +{ + pthread_cond_destroy(&m_condition); +} + +void ThreadCondition::wait(Mutex& mutex) +{ + if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0) + ASSERT(false); +} + +bool ThreadCondition::timedWait(Mutex& mutex, double secondsToWait) +{ + if (secondsToWait < 0.0) { + wait(mutex); + return true; + } + + int intervalSeconds = static_cast<int>(secondsToWait); + int intervalMicroseconds = static_cast<int>((secondsToWait - intervalSeconds) * 1000000.0); + + // Current time comes in sec/microsec + timeval currentTime; + gettimeofday(¤tTime, NULL); + + // Target time comes in sec/nanosec + timespec targetTime; + targetTime.tv_sec = currentTime.tv_sec + intervalSeconds; + targetTime.tv_nsec = (currentTime.tv_usec + intervalMicroseconds) * 1000; + if (targetTime.tv_nsec > 1000000000) { + targetTime.tv_nsec -= 1000000000; + targetTime.tv_sec++; + } + + return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0; +} + +void ThreadCondition::signal() +{ + if (pthread_cond_signal(&m_condition) != 0) + ASSERT(false); +} + +void ThreadCondition::broadcast() +{ + if (pthread_cond_broadcast(&m_condition) != 0) + ASSERT(false); +} + +} // namespace WTF + +#endif // USE(PTHREADS) diff --git a/JavaScriptCore/wtf/ThreadingQt.cpp b/JavaScriptCore/wtf/ThreadingQt.cpp new file mode 100644 index 0000000..b24f241 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingQt.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2007 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. + */ +#include "config.h" +#include "Threading.h" + +#include "HashMap.h" +#include "MainThread.h" +#include "MathExtras.h" + +#include <QCoreApplication> +#include <QMutex> +#include <QThread> +#include <QWaitCondition> + +namespace WTF { + +class ThreadPrivate : public QThread { +public: + ThreadPrivate(ThreadFunction entryPoint, void* data); + void run(); + void* getReturnValue() { return m_returnValue; } +private: + void* m_data; + ThreadFunction m_entryPoint; + void* m_returnValue; +}; + +ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint, void* data) + : m_data(data) + , m_entryPoint(entryPoint) + , m_returnValue(0) +{ +} + +void ThreadPrivate::run() +{ + m_returnValue = m_entryPoint(m_data); +} + + +Mutex* atomicallyInitializedStaticMutex; + +static ThreadIdentifier mainThreadIdentifier; + +static Mutex& threadMapMutex() +{ + static Mutex mutex; + return mutex; +} + +static HashMap<ThreadIdentifier, QThread*>& threadMap() +{ + static HashMap<ThreadIdentifier, QThread*> map; + return map; +} + +static ThreadIdentifier establishIdentifierForThread(QThread*& thread) +{ + MutexLocker locker(threadMapMutex()); + + static ThreadIdentifier identifierCount = 1; + + threadMap().add(identifierCount, thread); + + return identifierCount++; +} + +static void clearThreadForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + ASSERT(threadMap().contains(id)); + + threadMap().remove(id); +} + +static ThreadIdentifier identifierByQthreadHandle(QThread*& thread) +{ + MutexLocker locker(threadMapMutex()); + + HashMap<ThreadIdentifier, QThread*>::iterator i = threadMap().begin(); + for (; i != threadMap().end(); ++i) { + if (i->second == thread) + return i->first; + } + + return 0; +} + +static QThread* threadForIdentifier(ThreadIdentifier id) +{ + MutexLocker locker(threadMapMutex()); + + return threadMap().get(id); +} + +void initializeThreading() +{ + if(!atomicallyInitializedStaticMutex) { + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + wtf_random_init(); + QThread* mainThread = QCoreApplication::instance()->thread(); + mainThreadIdentifier = identifierByQthreadHandle(mainThread); + if (!mainThreadIdentifier) + mainThreadIdentifier = establishIdentifierForThread(mainThread); + initializeMainThread(); + } +} + +ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char*) +{ + ThreadPrivate* thread = new ThreadPrivate(entryPoint, data); + if (!thread) { + LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data); + return 0; + } + thread->start(); + + QThread* threadRef = static_cast<QThread*>(thread); + + return establishIdentifierForThread(threadRef); +} + +int waitForThreadCompletion(ThreadIdentifier threadID, void** result) +{ + ASSERT(threadID); + + QThread* thread = threadForIdentifier(threadID); + + bool res = thread->wait(); + + clearThreadForIdentifier(threadID); + *result = static_cast<ThreadPrivate*>(thread)->getReturnValue(); + + return !res; +} + +void detachThread(ThreadIdentifier) +{ +} + +ThreadIdentifier currentThread() +{ + QThread* currentThread = QThread::currentThread(); + if (ThreadIdentifier id = identifierByQthreadHandle(currentThread)) + return id; + return establishIdentifierForThread(currentThread); +} + +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} + +Mutex::Mutex() + : m_mutex(new QMutex()) +{ +} + +Mutex::~Mutex() +{ + delete m_mutex; +} + +void Mutex::lock() +{ + m_mutex->lock(); +} + +bool Mutex::tryLock() +{ + return m_mutex->tryLock(); +} + +void Mutex::unlock() +{ + m_mutex->unlock(); +} + +ThreadCondition::ThreadCondition() + : m_condition(new QWaitCondition()) +{ +} + +ThreadCondition::~ThreadCondition() +{ + delete m_condition; +} + +void ThreadCondition::wait(Mutex& mutex) +{ + m_condition->wait(mutex.impl()); +} + +bool ThreadCondition::timedWait(Mutex& mutex, double secondsToWait) +{ + if (secondsToWait < 0.0) { + wait(mutex); + return true; + } + + unsigned long millisecondsToWait = static_cast<unsigned long>(secondsToWait * 1000.0); + return m_condition->wait(mutex.impl(), millisecondsToWait); +} + +void ThreadCondition::signal() +{ + m_condition->wakeOne(); +} + +void ThreadCondition::broadcast() +{ + m_condition->wakeAll(); +} + +} // namespace WebCore diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp new file mode 100644 index 0000000..00ad149 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingWin.cpp @@ -0,0 +1,479 @@ +/* + * 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. + * + * ============================================================================= + * Note: The implementation of condition variables under the Windows + * plaform was based on that of the excellent BOOST C++ library. It + * has been rewritten to fit in with the WebKit architecture and to + * use its coding conventions. + * ============================================================================= + * + * The Boost license is virtually identical to the Apple variation at the + * top of this file, 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. + */ + +#include "config.h" +#include "Threading.h" + +#include "MainThread.h" +#include <process.h> +#include <windows.h> +#include <wtf/HashMap.h> +#include <wtf/MathExtras.h> + +#if PLATFORM(WIN) && USE(PTHREADS) +// Currently, Apple's Windows port uses a mixture of native and pthreads functions in FastMalloc. +// To ensure that thread-specific data is properly destroyed, we need to end each thread with pthread_exit(). +#include <pthread.h> +#endif + +namespace WTF { + +// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadName 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) + +static void setThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + // Visual Studio has a 31-character limit on thread names. Longer names will + // be truncated silently, but we'd like callers to know about the limit. + ASSERT_ARG(szThreadName, strlen(szThreadName) <= 31); + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info)); + } __except (EXCEPTION_CONTINUE_EXECUTION) { + } +} + +static Mutex* atomicallyInitializedStaticMutex; + +void lockAtomicallyInitializedStaticMutex() +{ + atomicallyInitializedStaticMutex->lock(); +} + +void unlockAtomicallyInitializedStaticMutex() +{ + atomicallyInitializedStaticMutex->unlock(); +} + +static ThreadIdentifier mainThreadIdentifier; + +static Mutex& threadMapMutex() +{ + static Mutex mutex; + return mutex; +} + +void initializeThreading() +{ + if (!atomicallyInitializedStaticMutex) { + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + wtf_random_init(); + initializeMainThread(); + mainThreadIdentifier = currentThread(); + setThreadName(mainThreadIdentifier, "Main Thread"); + } +} + +static HashMap<DWORD, HANDLE>& threadMap() +{ + static HashMap<DWORD, HANDLE> map; + return map; +} + +static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle) +{ + MutexLocker locker(threadMapMutex()); + 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); +} + +struct ThreadFunctionInvocation { + ThreadFunctionInvocation(ThreadFunction function, void* data) : function(function), data(data) {} + + ThreadFunction function; + void* data; +}; + +static unsigned __stdcall wtfThreadEntryPoint(void* param) +{ + ThreadFunctionInvocation invocation = *static_cast<ThreadFunctionInvocation*>(param); + delete static_cast<ThreadFunctionInvocation*>(param); + + void* result = invocation.function(invocation.data); + +#if PLATFORM(WIN) && USE(PTHREADS) + // pthreads-win32 knows how to work with threads created with Win32 or CRT functions, so it's OK to mix APIs. + pthread_exit(result); +#endif + + return reinterpret_cast<unsigned>(result); +} + +ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* threadName) +{ + unsigned threadIdentifier = 0; + ThreadIdentifier threadID = 0; + ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data); + HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &threadIdentifier)); + if (!threadHandle) { + LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno); + return 0; + } + + if (threadName) + setThreadName(threadIdentifier, threadName); + + threadID = static_cast<ThreadIdentifier>(threadIdentifier); + storeThreadHandleByIdentifier(threadIdentifier, threadHandle); + + return threadID; +} + +// 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) +{ + return createThread(entryPoint, data, 0); +} + +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); +} + +ThreadIdentifier currentThread() +{ + return static_cast<ThreadIdentifier>(::GetCurrentThreadId()); +} + +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} + +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); +} + +static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1); + +ThreadCondition::ThreadCondition() +{ + m_condition.m_timedOut = 0; + m_condition.m_blocked = 0; + m_condition.m_waitingForRemoval = 0; + m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0); + m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0); + m_condition.m_mutex = ::CreateMutex(0, 0, 0); + + if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) { + if (m_condition.m_gate) + ::CloseHandle(m_condition.m_gate); + if (m_condition.m_queue) + ::CloseHandle(m_condition.m_queue); + if (m_condition.m_mutex) + ::CloseHandle(m_condition.m_mutex); + } +} + +ThreadCondition::~ThreadCondition() +{ + ::CloseHandle(m_condition.m_gate); + ::CloseHandle(m_condition.m_queue); + ::CloseHandle(m_condition.m_mutex); +} + +void ThreadCondition::wait(Mutex& mutex) +{ + PlatformMutex& cs = mutex.impl(); + + // Enter the wait state. + DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + ++m_condition.m_blocked; + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); + ASSERT(res); + + ::LeaveCriticalSection(&cs.m_internalMutex); + + res = ::WaitForSingleObject(m_condition.m_queue, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + + res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + size_t wasWaiting = m_condition.m_waitingForRemoval; + size_t wasTimedOut = m_condition.m_timedOut; + if (wasWaiting != 0) { + if (--m_condition.m_waitingForRemoval == 0) { + if (m_condition.m_blocked != 0) { + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); // open m_gate + ASSERT(res); + wasWaiting = 0; + } + else if (m_condition.m_timedOut != 0) + m_condition.m_timedOut = 0; + } + } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) { + // timeout occured, normalize the m_condition.m_timedOut count + // this may occur if many calls to wait with a timeout are made and + // no call to notify_* is made + res = ::WaitForSingleObject(m_condition.m_gate, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + m_condition.m_blocked -= m_condition.m_timedOut; + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); + ASSERT(res); + m_condition.m_timedOut = 0; + } + res = ::ReleaseMutex(m_condition.m_mutex); + ASSERT(res); + + if (wasWaiting == 1) { + for (/**/ ; wasTimedOut; --wasTimedOut) { + // better now than spurious later + res = ::WaitForSingleObject(m_condition.m_queue, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + } + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); + ASSERT(res); + } + + ::EnterCriticalSection (&cs.m_internalMutex); +} + +bool ThreadCondition::timedWait(Mutex& mutex, double interval) +{ + // Empty for now + ASSERT(false); + return false; +} + +void ThreadCondition::signal() +{ + unsigned signals = 0; + + DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + + if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed + if (m_condition.m_blocked == 0) { + res = ::ReleaseMutex(m_condition.m_mutex); + ASSERT(res); + return; + } + + ++m_condition.m_waitingForRemoval; + --m_condition.m_blocked; + + signals = 1; + } else { + res = ::WaitForSingleObject(m_condition.m_gate, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + if (m_condition.m_blocked > m_condition.m_timedOut) { + if (m_condition.m_timedOut != 0) { + m_condition.m_blocked -= m_condition.m_timedOut; + m_condition.m_timedOut = 0; + } + signals = m_condition.m_waitingForRemoval = 1; + --m_condition.m_blocked; + } else { + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); + ASSERT(res); + } + } + + res =::ReleaseMutex(m_condition.m_mutex); + ASSERT(res); + + if (signals) { + res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0); + ASSERT(res); + } +} + +void ThreadCondition::broadcast() +{ + unsigned signals = 0; + + DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + + if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed + if (m_condition.m_blocked == 0) { + res = ::ReleaseMutex(m_condition.m_mutex); + ASSERT(res); + return; + } + + m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked); + m_condition.m_blocked = 0; + } else { + res = ::WaitForSingleObject(m_condition.m_gate, INFINITE); + ASSERT(res == WAIT_OBJECT_0); + if (m_condition.m_blocked > m_condition.m_timedOut) { + if (m_condition.m_timedOut != 0) { + m_condition.m_blocked -= m_condition.m_timedOut; + m_condition.m_timedOut = 0; + } + signals = m_condition.m_waitingForRemoval = m_condition.m_blocked; + m_condition.m_blocked = 0; + } else { + res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); + ASSERT(res); + } + } + + res = ::ReleaseMutex(m_condition.m_mutex); + ASSERT(res); + + if (signals) { + res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0); + ASSERT(res); + } +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/UnusedParam.h b/JavaScriptCore/wtf/UnusedParam.h index a599110..996f5c8 100644 --- a/JavaScriptCore/wtf/UnusedParam.h +++ b/JavaScriptCore/wtf/UnusedParam.h @@ -1,4 +1,3 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ /* * Copyright (C) 2006 Apple Computer, Inc. * @@ -27,4 +26,4 @@ #define UNUSED_PARAM(x) (void)x -#endif // WTF_UnusedParam_h +#endif /* WTF_UnusedParam_h */ diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 8fd412c..c0bc132 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * @@ -24,6 +23,8 @@ #include "Assertions.h" #include "FastMalloc.h" +#include "Noncopyable.h" +#include "NotFound.h" #include "VectorTraits.h" #include <limits> #include <stdlib.h> @@ -34,7 +35,33 @@ namespace WTF { using std::min; using std::max; - + + // WTF_ALIGN_OF / WTF_ALIGNED + #if COMPILER(GCC) || COMPILER(MINGW) + #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) && (((__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 <bool needsDestruction, typename T> class VectorDestructor; @@ -240,11 +267,10 @@ namespace WTF { }; template<typename T> - class VectorBufferBase { + class VectorBufferBase : Noncopyable { public: void allocateBuffer(size_t newCapacity) { - ASSERT(newCapacity >= m_capacity); m_capacity = newCapacity; if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T)) CRASH(); @@ -253,11 +279,14 @@ namespace WTF { void deallocateBuffer(T* bufferToDeallocate) { + if (m_buffer == bufferToDeallocate) + m_buffer = 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() @@ -322,6 +351,7 @@ namespace WTF { using Base::deallocateBuffer; using Base::buffer; + using Base::bufferSlot; using Base::capacity; using Base::releaseBuffer; @@ -343,8 +373,7 @@ namespace WTF { VectorBuffer(size_t capacity) : Base(inlineBuffer(), inlineCapacity) { - if (capacity > inlineCapacity) - allocateBuffer(capacity); + allocateBuffer(capacity); } ~VectorBuffer() @@ -352,7 +381,11 @@ namespace WTF { deallocateBuffer(buffer()); } - using Base::allocateBuffer; + void allocateBuffer(size_t newCapacity) + { + if (newCapacity > inlineCapacity) + Base::allocateBuffer(newCapacity); + } void deallocateBuffer(T* bufferToDeallocate) { @@ -362,6 +395,7 @@ namespace WTF { } using Base::buffer; + using Base::bufferSlot; using Base::capacity; T* releaseBuffer() @@ -376,16 +410,15 @@ namespace WTF { using Base::m_capacity; static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); - T* inlineBuffer() { return reinterpret_cast<T*>(&m_inlineBuffer); } + T* inlineBuffer() { return reinterpret_cast<T*>(m_inlineBuffer.buffer); } - // FIXME: Nothing guarantees this buffer is appropriately aligned to hold objects of type T. - char m_inlineBuffer[m_inlineBufferSize]; + AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; }; template<typename T, size_t inlineCapacity = 0> class Vector { private: - typedef VectorBuffer<T, inlineCapacity> Impl; + typedef VectorBuffer<T, inlineCapacity> Buffer; typedef VectorTypeOperations<T> TypeOperations; public: @@ -401,9 +434,10 @@ namespace WTF { explicit Vector(size_t size) : m_size(size) - , m_impl(size) + , m_buffer(size) { - TypeOperations::initialize(begin(), end()); + if (begin()) + TypeOperations::initialize(begin(), end()); } ~Vector() @@ -420,25 +454,26 @@ namespace WTF { Vector& operator=(const Vector<T, otherCapacity>&); size_t size() const { return m_size; } - size_t capacity() const { return m_impl.capacity(); } + size_t capacity() const { return m_buffer.capacity(); } bool isEmpty() const { return !size(); } T& at(size_t i) { ASSERT(i < size()); - return m_impl.buffer()[i]; + return m_buffer.buffer()[i]; } const T& at(size_t i) const { ASSERT(i < size()); - return m_impl.buffer()[i]; + 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_impl.buffer(); } - const T* data() const { return m_impl.buffer(); } + 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; } @@ -450,17 +485,20 @@ namespace WTF { T& last() { return at(size() - 1); } const T& last() const { return at(size() - 1); } + template<typename U> size_t find(const U&) const; + void shrink(size_t size); void grow(size_t size); void resize(size_t size); void reserveCapacity(size_t newCapacity); + void shrinkCapacity(size_t newCapacity); void clear() { if (m_size) shrink(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<typename U, size_t c> void append(const Vector<U, c>&); + template<size_t otherCapacity> void append(const Vector<T, otherCapacity>&); template<typename U> void insert(size_t position, const U*, size_t); template<typename U> void insert(size_t position, const U&); @@ -471,6 +509,7 @@ namespace WTF { 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() { @@ -480,9 +519,10 @@ namespace WTF { Vector(size_t size, const T& val) : m_size(size) - , m_impl(size) + , m_buffer(size) { - TypeOperations::uninitializedFill(begin(), end(), val); + if (begin()) + TypeOperations::uninitializedFill(begin(), end(), val); } void fill(const T&, size_t); @@ -495,7 +535,7 @@ namespace WTF { void swap(Vector<T, inlineCapacity>& other) { std::swap(m_size, other.m_size); - m_impl.swap(other.m_impl); + m_buffer.swap(other.m_buffer); } private: @@ -504,24 +544,26 @@ namespace WTF { template<typename U> U* expandCapacity(size_t newMinCapacity, U*); size_t m_size; - Impl m_impl; + Buffer m_buffer; }; template<typename T, size_t inlineCapacity> Vector<T, inlineCapacity>::Vector(const Vector& other) : m_size(other.size()) - , m_impl(other.capacity()) + , m_buffer(other.capacity()) { - TypeOperations::uninitializedCopy(other.begin(), other.end(), begin()); + 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_impl(other.capacity()) + , m_buffer(other.capacity()) { - TypeOperations::uninitializedCopy(other.begin(), other.end(), begin()); + if (begin()) + TypeOperations::uninitializedCopy(other.begin(), other.end(), begin()); } template<typename T, size_t inlineCapacity> @@ -535,6 +577,8 @@ namespace WTF { else if (other.size() > capacity()) { clear(); reserveCapacity(other.size()); + if (!begin()) + return *this; } std::copy(other.begin(), other.begin() + size(), begin()); @@ -556,6 +600,8 @@ namespace WTF { else if (other.size() > capacity()) { clear(); reserveCapacity(other.size()); + if (!begin()) + return *this; } std::copy(other.begin(), other.begin() + size(), begin()); @@ -566,6 +612,17 @@ namespace WTF { } 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> void Vector<T, inlineCapacity>::fill(const T& val, size_t newSize) { if (size() > newSize) @@ -573,6 +630,8 @@ namespace WTF { else if (newSize > capacity()) { clear(); reserveCapacity(newSize); + if (!begin()) + return; } std::fill(begin(), end(), val); @@ -621,7 +680,8 @@ namespace WTF { else { if (size > capacity()) expandCapacity(size); - TypeOperations::initialize(end(), begin() + size); + if (begin()) + TypeOperations::initialize(end(), begin() + size); } m_size = size; @@ -641,7 +701,8 @@ namespace WTF { ASSERT(size >= m_size); if (size > capacity()) expandCapacity(size); - TypeOperations::initialize(end(), begin() + size); + if (begin()) + TypeOperations::initialize(end(), begin() + size); m_size = size; } @@ -652,9 +713,29 @@ namespace WTF { return; T* oldBuffer = begin(); T* oldEnd = end(); - m_impl.allocateBuffer(newCapacity); - TypeOperations::move(oldBuffer, oldEnd, begin()); - m_impl.deallocateBuffer(oldBuffer); + m_buffer.allocateBuffer(newCapacity); + if (begin()) + TypeOperations::move(oldBuffer, oldEnd, begin()); + m_buffer.deallocateBuffer(oldBuffer); + } + + template<typename T, size_t inlineCapacity> + void Vector<T, inlineCapacity>::shrinkCapacity(size_t newCapacity) + { + if (newCapacity >= capacity()) + return; + + resize(min(m_size, 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); } // Templatizing these is better than just letting the conversion happen implicitly, @@ -665,8 +746,11 @@ namespace WTF { void Vector<T, inlineCapacity>::append(const U* data, size_t dataSize) { size_t newSize = m_size + dataSize; - if (newSize > capacity()) + if (newSize > capacity()) { data = expandCapacity(newSize, data); + if (!begin()) + return; + } T* dest = end(); for (size_t i = 0; i < dataSize; ++i) new (&dest[i]) T(data[i]); @@ -677,16 +761,19 @@ namespace WTF { inline void Vector<T, inlineCapacity>::append(const U& val) { const U* ptr = &val; - if (size() == capacity()) + if (size() == capacity()) { ptr = expandCapacity(size() + 1, ptr); + if (!begin()) + return; + } +#if COMPILER(MSVC7) // FIXME: MSVC7 generates compilation errors when trying to assign // a pointer to a Vector of its base class (i.e. can't downcast). So far // I've been unable to determine any logical reason for this, so I can - // only assume it is a bug with the compiler. Casting is very bad - // however because it subverts implicit conversions, so a better - // solution is direly needed. -#if COMPILER(MSVC7) + // only assume it is a bug with the compiler. Casting is a bad solution, + // however, because it subverts implicit conversions, so a better + // one is needed. new (end()) T(static_cast<T>(*ptr)); #else new (end()) T(*ptr); @@ -706,8 +793,11 @@ namespace WTF { ++m_size; } - template<typename T, size_t inlineCapacity> template<typename U, size_t c> - inline void Vector<T, inlineCapacity>::append(const Vector<U, c>& val) + // 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()); } @@ -717,8 +807,11 @@ namespace WTF { { ASSERT(position <= size()); size_t newSize = m_size + dataSize; - if (newSize > capacity()) + if (newSize > capacity()) { data = expandCapacity(newSize, data); + if (!begin()) + return; + } T* spot = begin() + position; TypeOperations::moveOverlapping(spot, end(), spot + dataSize); for (size_t i = 0; i < dataSize; ++i) @@ -731,8 +824,11 @@ namespace WTF { { ASSERT(position <= size()); const U* data = &val; - if (size() == capacity()) + if (size() == capacity()) { data = expandCapacity(size() + 1, data); + if (!begin()) + return; + } T* spot = begin() + position; TypeOperations::moveOverlapping(spot, end(), spot + 1); new (spot) T(*data); @@ -774,9 +870,21 @@ namespace WTF { } 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 T* Vector<T, inlineCapacity>::releaseBuffer() { - T* buffer = m_impl.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, @@ -785,7 +893,6 @@ namespace WTF { buffer = static_cast<T*>(fastMalloc(bytes)); memcpy(buffer, data(), bytes); } - ASSERT(buffer); m_size = 0; return buffer; } diff --git a/JavaScriptCore/wtf/VectorTraits.h b/JavaScriptCore/wtf/VectorTraits.h index c62a0bf..71aaec8 100644 --- a/JavaScriptCore/wtf/VectorTraits.h +++ b/JavaScriptCore/wtf/VectorTraits.h @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * This file is part of the KDE libraries * Copyright (C) 2006 Apple Computer, Inc. @@ -25,6 +24,7 @@ #include "RefPtr.h" #include <utility> +#include <memory> using std::pair; @@ -94,6 +94,9 @@ namespace WTF { template<typename P> struct VectorTraits<RefPtr<P> > : SimpleClassVectorTraits { }; + template<typename P> + struct VectorTraits<std::auto_ptr<P> > : SimpleClassVectorTraits { }; + template<typename First, typename Second> struct VectorTraits<pair<First, Second> > { diff --git a/JavaScriptCore/wtf/android/MainThreadAndroid.cpp b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp new file mode 100644 index 0000000..a6d8eb6 --- /dev/null +++ b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp @@ -0,0 +1,35 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "config.h" +#include "MainThread.h" +#include "jni/JavaSharedClient.h" + +namespace WTF { + +// Callback in the main thread. +static void timeoutFired(void *) +{ + dispatchFunctionsFromMainThread(); +} + +void scheduleDispatchFunctionsOnMainThread() +{ + WebCore::JavaSharedClient::EnqueueFunctionPtr(timeoutFired, NULL); +} + +} diff --git a/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp b/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp new file mode 100644 index 0000000..a6e061f --- /dev/null +++ b/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp @@ -0,0 +1,49 @@ +/* + * 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 { + +static gboolean timeoutFired(gpointer) +{ + dispatchFunctionsFromMainThread(); + return FALSE; +} + +void scheduleDispatchFunctionsOnMainThread() +{ + g_timeout_add(0, timeoutFired, 0); +} + + +} diff --git a/JavaScriptCore/wtf/mac/MainThreadMac.mm b/JavaScriptCore/wtf/mac/MainThreadMac.mm new file mode 100644 index 0000000..b04ef0e --- /dev/null +++ b/JavaScriptCore/wtf/mac/MainThreadMac.mm @@ -0,0 +1,57 @@ +/* + * 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 <Foundation/NSThread.h> + +@interface WTFMainThreadCaller : NSObject { +} +- (void)call; +@end + +@implementation WTFMainThreadCaller + +- (void)call +{ + WTF::dispatchFunctionsFromMainThread(); +} + +@end // implementation WTFMainThreadCaller + +namespace WTF { + +void scheduleDispatchFunctionsOnMainThread() +{ + WTFMainThreadCaller *caller = [[WTFMainThreadCaller alloc] init]; + [caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; + [caller release]; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/qt/MainThreadQt.cpp b/JavaScriptCore/wtf/qt/MainThreadQt.cpp new file mode 100644 index 0000000..1914600 --- /dev/null +++ b/JavaScriptCore/wtf/qt/MainThreadQt.cpp @@ -0,0 +1,69 @@ +/* + * 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 <QtCore/QObject> +#include <QtCore/QCoreApplication> + + +namespace WTF { + +class MainThreadInvoker : public QObject { + Q_OBJECT +public: + MainThreadInvoker(); + +private Q_SLOTS: + void dispatch(); +}; + +MainThreadInvoker::MainThreadInvoker() +{ + moveToThread(QCoreApplication::instance()->thread()); +} + +void MainThreadInvoker::dispatch() +{ + dispatchFunctionsFromMainThread(); +} + +Q_GLOBAL_STATIC(MainThreadInvoker, webkit_main_thread_invoker) + + +void scheduleDispatchFunctionsOnMainThread() +{ + QMetaObject::invokeMethod(webkit_main_thread_invoker(), "dispatch", Qt::QueuedConnection); +} + +} + +#include "MainThreadQt.moc" diff --git a/JavaScriptCore/wtf/unicode/Collator.h b/JavaScriptCore/wtf/unicode/Collator.h new file mode 100644 index 0000000..f04779d --- /dev/null +++ b/JavaScriptCore/wtf/unicode/Collator.h @@ -0,0 +1,67 @@ +/* + * 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 <memory> +#include <wtf/Noncopyable.h> +#include <wtf/unicode/Unicode.h> + +#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION +struct UCollator; +#endif + +namespace WTF { + + class Collator : Noncopyable { + 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 std::auto_ptr<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/JavaScriptCore/wtf/unicode/CollatorDefault.cpp b/JavaScriptCore/wtf/unicode/CollatorDefault.cpp new file mode 100644 index 0000000..eddbe53 --- /dev/null +++ b/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) +{ +} + +std::auto_ptr<Collator> Collator::userDefault() +{ + return std::auto_ptr<Collator>(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/JavaScriptCore/wtf/unicode/Unicode.h b/JavaScriptCore/wtf/unicode/Unicode.h index f890afc..9cd3555 100644 --- a/JavaScriptCore/wtf/unicode/Unicode.h +++ b/JavaScriptCore/wtf/unicode/Unicode.h @@ -1,4 +1,3 @@ -// -*- c-basic-offset: 2 -*- /* * This file is part of the KDE libraries * Copyright (C) 2006 George Staikos <staikos@kde.org> diff --git a/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp new file mode 100644 index 0000000..a8bcc81 --- /dev/null +++ b/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp @@ -0,0 +1,144 @@ +/* + * 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 PLATFORM(DARWIN) +#include <CoreFoundation/CoreFoundation.h> +#endif + +namespace WTF { + +static UCollator* cachedCollator; +static Mutex& cachedCollatorMutex() +{ + AtomicallyInitializedStatic(Mutex, mutex); + return mutex; +} + +Collator::Collator(const char* locale) + : m_collator(0) + , m_locale(locale ? strdup(locale) : 0) + , m_lowerFirst(false) +{ +} + +std::auto_ptr<Collator> Collator::userDefault() +{ +#if PLATFORM(DARWIN) && PLATFORM(CF) + // Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work. + CFStringRef collationOrder = (CFStringRef)CFPreferencesCopyValue(CFSTR("AppleCollationOrder"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + char buf[256]; + if (collationOrder) { + CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII); + CFRelease(collationOrder); + return std::auto_ptr<Collator>(new Collator(buf)); + } else + return std::auto_ptr<Collator>(new Collator("")); +#else + return std::auto_ptr<Collator>(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/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h index cc9ab8c..7cdc55c 100644 --- a/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h +++ b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h @@ -1,9 +1,7 @@ -// -*- c-basic-offset: 2 -*- /* - * This file is part of the KDE libraries * 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 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 @@ -25,215 +23,197 @@ #ifndef KJS_UNICODE_ICU_H #define KJS_UNICODE_ICU_H +#include <stdlib.h> #include <unicode/uchar.h> #include <unicode/ustring.h> #include <unicode/utf16.h> -#include <stdlib.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 isFormatChar(UChar32 c) - { - return u_charType(c) == U_FORMAT_CHAR; - } - - inline bool isSeparatorSpace(UChar32 c) - { - return u_charType(c) == U_SPACE_SEPARATOR; - } - - inline bool isPrintableChar(UChar32 c) - { - return !!u_isprint(c); - } - - inline bool isDigit(UChar32 c) - { - return !!u_isdigit(c); - } - - inline bool isPunct(UChar32 c) - { - return !!u_ispunct(c); - } - - 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 int digitValue(UChar32 c) - { - return u_charDigitValue(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); - } - - } +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 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 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 -// vim: ts=2 sw=2 et diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index 0fbd869..d285a8f 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -1,5 +1,4 @@ /* - * This file is part of the KDE libraries * Copyright (C) 2006 George Staikos <staikos@kde.org> * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> * @@ -31,6 +30,7 @@ #include <stdint.h> #if QT_VERSION >= 0x040300 +QT_BEGIN_NAMESPACE namespace QUnicodeTables { struct Properties { ushort category : 8; @@ -53,6 +53,7 @@ namespace QUnicodeTables { Q_CORE_EXPORT const Properties * QT_FASTCALL properties(uint ucs4); Q_CORE_EXPORT const Properties * QT_FASTCALL properties(ushort ucs2); } +QT_END_NAMESPACE #endif // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h @@ -93,455 +94,432 @@ typedef uint32_t UChar32; #define U_MASK(x) ((uint32_t)1<<(x)) 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), - }; +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), +}; #if QT_VERSION >= 0x040300 - // FIXME: handle surrogates correctly in all methods - inline UChar32 toLower(UChar32 ch) - { - return QChar::toLower(ch); - } +// FIXME: handle surrogates correctly in all methods - 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; - UChar *re = result + resultLength; - - // this avoids one out of bounds check in the loop - if (QChar(*s).isLowSurrogate()) - *r++ = *s++; - - int needed = 0; - while (s < e && r < re) { - 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 (r == re) { - needed += qstring.length() - i; - break; - } - *r = qstring.at(i).unicode(); - ++r; - } +inline UChar32 toLower(UChar32 ch) +{ + return QChar::toLower(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 { - *r = *s + prop->lowerCaseDiff; - ++r; + qstring += QChar(*(s-1)); + qstring += QChar(*s); } - ++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; } - if (s < e) - needed += e - s; - *error = (needed != 0); - if (r < re) - *r = 0; - return (r - result) + needed; - } + ++s; + } + if (s < e) + needed += e - s; + *error = (needed != 0); + if (rindex < uint(resultLength)) + r[rindex] = 0; + return rindex + needed; +} - inline UChar32 toUpper(UChar32 ch) - { - return QChar::toUpper(ch); - } +inline UChar32 toUpper(UChar32 ch) +{ + return QChar::toUpper(ch); +} - 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; - UChar *re = result + resultLength; - - // this avoids one out of bounds check in the loop - if (QChar(*s).isLowSurrogate()) - *r++ = *s++; - - int needed = 0; - while (s < e && r < re) { - 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 (r == re) { - needed += qstring.length() - i; - break; - } - *r = qstring.at(i).unicode(); - ++r; - } +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 { - *r = *s + prop->upperCaseDiff; - ++r; + 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; } - ++s; + } else { + if (r) + r[rindex] = *s + prop->upperCaseDiff; + ++rindex; } - if (s < e) - needed += e - s; - *error = (needed != 0); - if (r < re) - *r = 0; - return (r - result) + needed; - } + ++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(c); - } +inline int toTitleCase(UChar32 c) +{ + return QChar::toTitleCase(c); +} - inline UChar32 foldCase(UChar32 c) - { - return QChar::toCaseFolded(c); - } +inline UChar32 foldCase(UChar32 c) +{ + return QChar::toCaseFolded(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) { +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(src[i]); - return srcLength; - } - - inline bool isFormatChar(UChar32 c) - { - return QChar::category(c) == QChar::Other_Format; - } - - 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(c)) & test); } + for (int i = 0; i < srcLength; ++i) + result[i] = QChar::toCaseFolded(ushort(src[i])); + return srcLength; +} - inline bool isSeparatorSpace(UChar32 c) - { - return QChar::category(c) == QChar::Separator_Space; - } +inline bool isArabicChar(UChar32 c) +{ + return c >= 0x0600 && c <= 0x06FF; +} - 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(c)) & test; - } +inline bool isPrintableChar(UChar32 c) +{ + const uint test = U_MASK(QChar::Other_Control) | + U_MASK(QChar::Other_NotAssigned); + return !(U_MASK(QChar::category(c)) & test); +} - inline bool isDigit(UChar32 c) - { - return QChar::category(c) == QChar::Number_DecimalDigit; - } +inline bool isSeparatorSpace(UChar32 c) +{ + return QChar::category(c) == QChar::Separator_Space; +} - inline bool isLower(UChar32 c) - { - return QChar::category(c) == QChar::Letter_Lowercase; - } +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(c)) & test; +} - inline int digitValue(UChar32 c) - { - return QChar::digitValue(c); - } +inline bool isLower(UChar32 c) +{ + return QChar::category(c) == QChar::Letter_Lowercase; +} - inline UChar32 mirroredChar(UChar32 c) - { - return QChar::mirroredChar(c); - } +inline UChar32 mirroredChar(UChar32 c) +{ + return QChar::mirroredChar(c); +} - inline uint8_t combiningClass(UChar32 c) - { - return QChar::combiningClass(c); - } +inline uint8_t combiningClass(UChar32 c) +{ + return QChar::combiningClass(c); +} - inline DecompositionType decompositionType(UChar32 c) - { - return (DecompositionType)QChar::decompositionTag(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(a[i]); - uint c2 = QChar::toCaseFolded(b[i]); - if (c1 != c2) - return c1 - c2; - } - return 0; +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(c); - } +inline Direction direction(UChar32 c) +{ + return (Direction)QChar::direction(c); +} - inline CharCategory category(UChar32 c) - { - return (CharCategory) U_MASK(QChar::category(c)); - } +inline CharCategory category(UChar32 c) +{ + return (CharCategory) U_MASK(QChar::category(c)); +} #else - inline UChar32 toLower(UChar32 ch) - { - if (ch > 0xffff) +inline UChar32 toLower(UChar32 ch) +{ + if (ch > 0xffff) return ch; - return QChar((unsigned short)ch).toLower().unicode(); - } + return QChar((unsigned short)ch).toLower().unicode(); +} - inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) - { - *error = false; - if (resultLength < srcLength) { - *error = true; - return srcLength; - } - for (int i = 0; i < srcLength; ++i) - result[i] = QChar(src[i]).toLower().unicode(); - return srcLength; - } +inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +{ + *error = false; + if (resultLength < srcLength) { + *error = true; + return srcLength; + } + for (int i = 0; i < srcLength; ++i) + result[i] = QChar(src[i]).toLower().unicode(); + return srcLength; +} - inline UChar32 toUpper(UChar32 ch) - { - if (ch > 0xffff) +inline UChar32 toUpper(UChar32 ch) +{ + if (ch > 0xffff) return ch; - return QChar((unsigned short)ch).toUpper().unicode(); - } + return QChar((unsigned short)ch).toUpper().unicode(); +} - inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) - { - *error = false; - if (resultLength < srcLength) { +inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +{ + *error = false; + if (resultLength < srcLength) { *error = true; return srcLength; - } - for (int i = 0; i < srcLength; ++i) - result[i] = QChar(src[i]).toUpper().unicode(); - return srcLength; } + for (int i = 0; i < srcLength; ++i) + result[i] = QChar(src[i]).toUpper().unicode(); + return srcLength; +} - inline int toTitleCase(UChar32 c) - { - if (c > 0xffff) +inline int toTitleCase(UChar32 c) +{ + if (c > 0xffff) return c; - return QChar((unsigned short)c).toUpper().unicode(); - } + return QChar((unsigned short)c).toUpper().unicode(); +} - inline UChar32 foldCase(UChar32 c) - { - if (c > 0xffff) +inline UChar32 foldCase(UChar32 c) +{ + if (c > 0xffff) return c; - return QChar((unsigned short)c).toLower().unicode(); - } - - inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) - { - return toLower(result, resultLength, src, srcLength, error); - } - - inline bool isFormatChar(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Other_Format; - } - - inline bool isPrintableChar(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint(); - } + return QChar((unsigned short)c).toLower().unicode(); +} - inline bool isArabicChar(UChar32 c) - { - return c >= 0x0600 && c <= 0x06FF; - } +inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) +{ + return toLower(result, resultLength, src, srcLength, error); +} - inline bool isSeparatorSpace(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space; - } +inline bool isPrintableChar(UChar32 c) +{ + return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint(); +} - inline bool isPunct(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct(); - } +inline bool isArabicChar(UChar32 c) +{ + return c >= 0x0600 && c <= 0x06FF; +} - inline bool isDigit(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isDigit(); - } +inline bool isSeparatorSpace(UChar32 c) +{ + return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space; +} - inline bool isLower(UChar32 c) - { - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase; - } +inline bool isPunct(UChar32 c) +{ + return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct(); +} - inline int digitValue(UChar32 c) - { - if (c > 0xffff) - return 0; - return QChar(c).digitValue(); - } +inline bool isLower(UChar32 c) +{ + return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase; +} - inline UChar32 mirroredChar(UChar32 c) - { - if (c > 0xffff) +inline UChar32 mirroredChar(UChar32 c) +{ + if (c > 0xffff) return c; - return QChar(c).mirroredChar().unicode(); - } + return QChar(c).mirroredChar().unicode(); +} - inline uint8_t combiningClass(UChar32 c) - { - if (c > 0xffff) +inline uint8_t combiningClass(UChar32 c) +{ + if (c > 0xffff) return 0; - return QChar((unsigned short)c).combiningClass(); - } + return QChar((unsigned short)c).combiningClass(); +} - inline DecompositionType decompositionType(UChar32 c) - { - if (c > 0xffff) +inline DecompositionType decompositionType(UChar32 c) +{ + if (c > 0xffff) return DecompositionNone; - return (DecompositionType)QChar(c).decompositionTag(); - } + return (DecompositionType)QChar(c).decompositionTag(); +} - inline int umemcasecmp(const UChar* a, const UChar* b, int len) - { - for (int i = 0; i < len; ++i) { +inline int umemcasecmp(const UChar* a, const UChar* b, int len) +{ + for (int i = 0; i < len; ++i) { QChar c1 = QChar(a[i]).toLower(); QChar c2 = QChar(b[i]).toLower(); if (c1 != c2) - return c1.unicode() - c2.unicode(); - } - return 0; + return c1.unicode() - c2.unicode(); } + return 0; +} - inline Direction direction(UChar32 c) - { - if (c > 0xffff) +inline Direction direction(UChar32 c) +{ + if (c > 0xffff) return LeftToRight; - return (Direction)QChar(c).direction(); - } + return (Direction)QChar(c).direction(); +} - inline CharCategory category(UChar32 c) - { - if (c > 0xffff) +inline CharCategory category(UChar32 c) +{ + if (c > 0xffff) return NoCategory; - return (CharCategory) U_MASK(QChar(c).category()); - } + return (CharCategory) U_MASK(QChar(c).category()); +} #endif - } -} +} } #endif -// vim: ts=2 sw=2 et diff --git a/JavaScriptCore/wtf/win/MainThreadWin.cpp b/JavaScriptCore/wtf/win/MainThreadWin.cpp new file mode 100644 index 0000000..9f05d22 --- /dev/null +++ b/JavaScriptCore/wtf/win/MainThreadWin.cpp @@ -0,0 +1,76 @@ +/* + * 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 "Assertions.h" +#include "Threading.h" +#include <windows.h> + +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 initializeMainThread() +{ + if (threadingWindowHandle) + return; + + mainThreadFunctionQueueMutex(); + + WNDCLASSEX wcex; + memset(&wcex, 0, sizeof(WNDCLASSEX)); + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpfnWndProc = ThreadingWindowWndProc; + wcex.lpszClassName = kThreadingWindowClassName; + RegisterClassEx(&wcex); + + threadingWindowHandle = CreateWindow(kThreadingWindowClassName, 0, 0, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, 0, 0); + threadingFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.MainThreadFired"); +} + +void scheduleDispatchFunctionsOnMainThread() +{ + ASSERT(threadingWindowHandle); + PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0); +} + +} // namespace WebCore diff --git a/JavaScriptCore/wtf/wx/MainThreadWx.cpp b/JavaScriptCore/wtf/wx/MainThreadWx.cpp new file mode 100644 index 0000000..3166331 --- /dev/null +++ b/JavaScriptCore/wtf/wx/MainThreadWx.cpp @@ -0,0 +1,38 @@ +/* + * 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" + +namespace WTF { + +void scheduleDispatchFunctionsOnMainThread() +{ +} + +} |