OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 RUNTIME_ASSERT(obj->IsNumber()); \ | 85 RUNTIME_ASSERT(obj->IsNumber()); \ |
86 double name = (obj)->Number(); | 86 double name = (obj)->Number(); |
87 | 87 |
88 // Call the specified converter on the object *comand store the result in | 88 // Call the specified converter on the object *comand store the result in |
89 // a variable of the specified type with the given name. If the | 89 // a variable of the specified type with the given name. If the |
90 // object is not a Number call IllegalOperation and return. | 90 // object is not a Number call IllegalOperation and return. |
91 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ | 91 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ |
92 RUNTIME_ASSERT(obj->IsNumber()); \ | 92 RUNTIME_ASSERT(obj->IsNumber()); \ |
93 type name = NumberTo##Type(obj); | 93 type name = NumberTo##Type(obj); |
94 | 94 |
95 // Non-reentrant string buffer for efficient general use in this file. | |
96 static StaticResource<StringInputBuffer> runtime_string_input_buffer; | |
97 | |
98 | |
99 static Object* DeepCopyBoilerplate(JSObject* boilerplate) { | 95 static Object* DeepCopyBoilerplate(JSObject* boilerplate) { |
100 StackLimitCheck check; | 96 StackLimitCheck check; |
101 if (check.HasOverflowed()) return Top::StackOverflow(); | 97 if (check.HasOverflowed()) return Top::StackOverflow(); |
102 | 98 |
103 Object* result = Heap::CopyJSObject(boilerplate); | 99 Object* result = Heap::CopyJSObject(boilerplate); |
104 if (result->IsFailure()) return result; | 100 if (result->IsFailure()) return result; |
105 JSObject* copy = JSObject::cast(result); | 101 JSObject* copy = JSObject::cast(result); |
106 | 102 |
107 // Deep copy local properties. | 103 // Deep copy local properties. |
108 if (copy->HasFastProperties()) { | 104 if (copy->HasFastProperties()) { |
(...skipping 1794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 return biased_good_suffix_shift_[index]; | 1899 return biased_good_suffix_shift_[index]; |
1904 } | 1900 } |
1905 private: | 1901 private: |
1906 int suffixes_[kBMMaxShift + 1]; | 1902 int suffixes_[kBMMaxShift + 1]; |
1907 int good_suffix_shift_[kBMMaxShift + 1]; | 1903 int good_suffix_shift_[kBMMaxShift + 1]; |
1908 int* biased_suffixes_; | 1904 int* biased_suffixes_; |
1909 int* biased_good_suffix_shift_; | 1905 int* biased_good_suffix_shift_; |
1910 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); | 1906 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); |
1911 }; | 1907 }; |
1912 | 1908 |
1913 // buffers reused by BoyerMoore | 1909 class RuntimeData { |
1914 static int bad_char_occurrence[kBMAlphabetSize]; | 1910 public: |
1915 static BMGoodSuffixBuffers bmgs_buffers; | 1911 // Non-reentrant string buffer for efficient general use in this file. |
| 1912 StaticResource<StringInputBuffer> runtime_string_input_buffer_; |
| 1913 // buffers reused by BoyerMoore |
| 1914 int bad_char_occurrence_[kBMAlphabetSize]; |
| 1915 BMGoodSuffixBuffers bmgs_buffers_; |
| 1916 StringInputBuffer buf1_; |
| 1917 StringInputBuffer buf2_; |
| 1918 |
| 1919 unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping_; |
| 1920 unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping_; |
| 1921 |
| 1922 // Arrays for the individual characters of the two Smis. Smis are |
| 1923 // 31 bit integers and 10 decimal digits are therefore enough. |
| 1924 int x_elms_[10]; |
| 1925 int y_elms_[10]; |
| 1926 |
| 1927 StringInputBuffer bufx_; |
| 1928 StringInputBuffer bufy_; |
| 1929 |
| 1930 RuntimeData() {} |
| 1931 DISALLOW_COPY_AND_ASSIGN(RuntimeData); |
| 1932 }; |
1916 | 1933 |
1917 // Compute the bad-char table for Boyer-Moore in the static buffer. | 1934 // Compute the bad-char table for Boyer-Moore in the static buffer. |
1918 template <typename pchar> | 1935 template <typename pchar> |
1919 static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern, | 1936 static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern, |
1920 int start) { | 1937 int start) { |
1921 // Run forwards to populate bad_char_table, so that *last* instance | 1938 // Run forwards to populate bad_char_table, so that *last* instance |
1922 // of character equivalence class is the one registered. | 1939 // of character equivalence class is the one registered. |
1923 // Notice: Doesn't include the last character. | 1940 // Notice: Doesn't include the last character. |
1924 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 | 1941 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 |
1925 : kBMAlphabetSize; | 1942 : kBMAlphabetSize; |
| 1943 int* const bad_char_occurrence = v8_context()->runtime_data_-> |
| 1944 bad_char_occurrence_; |
| 1945 |
1926 if (start == 0) { // All patterns less than kBMMaxShift in length. | 1946 if (start == 0) { // All patterns less than kBMMaxShift in length. |
1927 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); | 1947 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); |
1928 } else { | 1948 } else { |
1929 for (int i = 0; i < table_size; i++) { | 1949 for (int i = 0; i < table_size; i++) { |
1930 bad_char_occurrence[i] = start - 1; | 1950 bad_char_occurrence[i] = start - 1; |
1931 } | 1951 } |
1932 } | 1952 } |
1933 for (int i = start; i < pattern.length() - 1; i++) { | 1953 for (int i = start; i < pattern.length() - 1; i++) { |
1934 pchar c = pattern[i]; | 1954 pchar c = pattern[i]; |
1935 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; | 1955 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; |
1936 bad_char_occurrence[bucket] = i; | 1956 bad_char_occurrence[bucket] = i; |
1937 } | 1957 } |
1938 } | 1958 } |
1939 | 1959 |
1940 template <typename pchar> | 1960 template <typename pchar> |
1941 static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern, | 1961 static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern, |
1942 int start) { | 1962 int start) { |
1943 int m = pattern.length(); | 1963 int m = pattern.length(); |
1944 int len = m - start; | 1964 int len = m - start; |
1945 // Compute Good Suffix tables. | 1965 // Compute Good Suffix tables. |
| 1966 BMGoodSuffixBuffers& bmgs_buffers = |
| 1967 v8_context()->runtime_data_->bmgs_buffers_; |
1946 bmgs_buffers.init(m); | 1968 bmgs_buffers.init(m); |
1947 | 1969 |
1948 bmgs_buffers.shift(m-1) = 1; | 1970 bmgs_buffers.shift(m-1) = 1; |
1949 bmgs_buffers.suffix(m) = m + 1; | 1971 bmgs_buffers.suffix(m) = m + 1; |
1950 pchar last_char = pattern[m - 1]; | 1972 pchar last_char = pattern[m - 1]; |
1951 int suffix = m + 1; | 1973 int suffix = m + 1; |
1952 for (int i = m; i > start;) { | 1974 for (int i = m; i > start;) { |
1953 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { | 1975 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { |
1954 if (bmgs_buffers.shift(suffix) == len) { | 1976 if (bmgs_buffers.shift(suffix) == len) { |
1955 bmgs_buffers.shift(suffix) = suffix - i; | 1977 bmgs_buffers.shift(suffix) = suffix - i; |
(...skipping 25 matching lines...) Expand all Loading... |
1981 bmgs_buffers.shift(i) = suffix - start; | 2003 bmgs_buffers.shift(i) = suffix - start; |
1982 } | 2004 } |
1983 if (i == suffix) { | 2005 if (i == suffix) { |
1984 suffix = bmgs_buffers.suffix(suffix); | 2006 suffix = bmgs_buffers.suffix(suffix); |
1985 } | 2007 } |
1986 } | 2008 } |
1987 } | 2009 } |
1988 } | 2010 } |
1989 | 2011 |
1990 template <typename schar, typename pchar> | 2012 template <typename schar, typename pchar> |
1991 static inline int CharOccurrence(int char_code) { | 2013 static inline int CharOccurrence(int char_code, RuntimeData* data) { |
1992 if (sizeof(schar) == 1) { | 2014 if (sizeof(schar) == 1) { |
1993 return bad_char_occurrence[char_code]; | 2015 return data->bad_char_occurrence_[char_code]; |
1994 } | 2016 } |
1995 if (sizeof(pchar) == 1) { | 2017 if (sizeof(pchar) == 1) { |
1996 if (char_code > String::kMaxAsciiCharCode) { | 2018 if (char_code > String::kMaxAsciiCharCode) { |
1997 return -1; | 2019 return -1; |
1998 } | 2020 } |
1999 return bad_char_occurrence[char_code]; | 2021 return data->bad_char_occurrence_[char_code]; |
2000 } | 2022 } |
2001 return bad_char_occurrence[char_code % kBMAlphabetSize]; | 2023 return data->bad_char_occurrence_[char_code % kBMAlphabetSize]; |
2002 } | 2024 } |
2003 | 2025 |
2004 // Restricted simplified Boyer-Moore string matching. | 2026 // Restricted simplified Boyer-Moore string matching. |
2005 // Uses only the bad-shift table of Boyer-Moore and only uses it | 2027 // Uses only the bad-shift table of Boyer-Moore and only uses it |
2006 // for the character compared to the last character of the needle. | 2028 // for the character compared to the last character of the needle. |
2007 template <typename schar, typename pchar> | 2029 template <typename schar, typename pchar> |
2008 static int BoyerMooreHorspool(Vector<const schar> subject, | 2030 static int BoyerMooreHorspool(Vector<const schar> subject, |
2009 Vector<const pchar> pattern, | 2031 Vector<const pchar> pattern, |
2010 int start_index, | 2032 int start_index, |
2011 bool* complete) { | 2033 bool* complete) { |
2012 int n = subject.length(); | 2034 int n = subject.length(); |
2013 int m = pattern.length(); | 2035 int m = pattern.length(); |
2014 // Only preprocess at most kBMMaxShift last characters of pattern. | 2036 // Only preprocess at most kBMMaxShift last characters of pattern. |
2015 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; | 2037 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; |
2016 | 2038 |
2017 BoyerMoorePopulateBadCharTable(pattern, start); | 2039 BoyerMoorePopulateBadCharTable(pattern, start); |
2018 | 2040 |
| 2041 RuntimeData* const data = v8_context()->runtime_data_; |
2019 int badness = -m; // How bad we are doing without a good-suffix table. | 2042 int badness = -m; // How bad we are doing without a good-suffix table. |
2020 int idx; // No matches found prior to this index. | 2043 int idx; // No matches found prior to this index. |
2021 pchar last_char = pattern[m - 1]; | 2044 pchar last_char = pattern[m - 1]; |
2022 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char); | 2045 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char, data); |
2023 // Perform search | 2046 // Perform search |
2024 for (idx = start_index; idx <= n - m;) { | 2047 for (idx = start_index; idx <= n - m;) { |
2025 int j = m - 1; | 2048 int j = m - 1; |
2026 int c; | 2049 int c; |
2027 while (last_char != (c = subject[idx + j])) { | 2050 while (last_char != (c = subject[idx + j])) { |
2028 int bc_occ = CharOccurrence<schar, pchar>(c); | 2051 int bc_occ = CharOccurrence<schar, pchar>(c, data); |
2029 int shift = j - bc_occ; | 2052 int shift = j - bc_occ; |
2030 idx += shift; | 2053 idx += shift; |
2031 badness += 1 - shift; // at most zero, so badness cannot increase. | 2054 badness += 1 - shift; // at most zero, so badness cannot increase. |
2032 if (idx > n - m) { | 2055 if (idx > n - m) { |
2033 *complete = true; | 2056 *complete = true; |
2034 return -1; | 2057 return -1; |
2035 } | 2058 } |
2036 } | 2059 } |
2037 j--; | 2060 j--; |
2038 while (j >= 0 && pattern[j] == (subject[idx + j])) j--; | 2061 while (j >= 0 && pattern[j] == (subject[idx + j])) j--; |
(...skipping 23 matching lines...) Expand all Loading... |
2062 Vector<const pchar> pattern, | 2085 Vector<const pchar> pattern, |
2063 int idx) { | 2086 int idx) { |
2064 int n = subject.length(); | 2087 int n = subject.length(); |
2065 int m = pattern.length(); | 2088 int m = pattern.length(); |
2066 // Only preprocess at most kBMMaxShift last characters of pattern. | 2089 // Only preprocess at most kBMMaxShift last characters of pattern. |
2067 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; | 2090 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; |
2068 | 2091 |
2069 // Build the Good Suffix table and continue searching. | 2092 // Build the Good Suffix table and continue searching. |
2070 BoyerMoorePopulateGoodSuffixTable(pattern, start); | 2093 BoyerMoorePopulateGoodSuffixTable(pattern, start); |
2071 pchar last_char = pattern[m - 1]; | 2094 pchar last_char = pattern[m - 1]; |
| 2095 RuntimeData* runtime_data = v8_context()->runtime_data_; |
| 2096 BMGoodSuffixBuffers& bmgs_buffers = runtime_data->bmgs_buffers_; |
2072 // Continue search from i. | 2097 // Continue search from i. |
2073 while (idx <= n - m) { | 2098 while (idx <= n - m) { |
2074 int j = m - 1; | 2099 int j = m - 1; |
2075 schar c; | 2100 schar c; |
2076 while (last_char != (c = subject[idx + j])) { | 2101 while (last_char != (c = subject[idx + j])) { |
2077 int shift = j - CharOccurrence<schar, pchar>(c); | 2102 int shift = j - CharOccurrence<schar, pchar>(c, runtime_data); |
2078 idx += shift; | 2103 idx += shift; |
2079 if (idx > n - m) { | 2104 if (idx > n - m) { |
2080 return -1; | 2105 return -1; |
2081 } | 2106 } |
2082 } | 2107 } |
2083 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--; | 2108 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--; |
2084 if (j < 0) { | 2109 if (j < 0) { |
2085 return idx; | 2110 return idx; |
2086 } else if (j < start) { | 2111 } else if (j < start) { |
2087 // we have matched more than our tables allow us to be smart about. | 2112 // we have matched more than our tables allow us to be smart about. |
2088 // Fall back on BMH shift. | 2113 // Fall back on BMH shift. |
2089 idx += m - 1 - CharOccurrence<schar, pchar>(last_char); | 2114 idx += m - 1 - CharOccurrence<schar, pchar>(last_char, runtime_data); |
2090 } else { | 2115 } else { |
2091 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift. | 2116 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift. |
2092 int bc_occ = CharOccurrence<schar, pchar>(c); | 2117 int bc_occ = CharOccurrence<schar, pchar>(c, runtime_data); |
2093 int shift = j - bc_occ; // Bad-char shift. | 2118 int shift = j - bc_occ; // Bad-char shift. |
2094 if (gs_shift > shift) { | 2119 if (gs_shift > shift) { |
2095 shift = gs_shift; | 2120 shift = gs_shift; |
2096 } | 2121 } |
2097 idx += shift; | 2122 idx += shift; |
2098 } | 2123 } |
2099 } | 2124 } |
2100 | 2125 |
2101 return -1; | 2126 return -1; |
2102 } | 2127 } |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2352 | 2377 |
2353 // No need to flatten if we are going to find the answer on the first | 2378 // No need to flatten if we are going to find the answer on the first |
2354 // character. At this point we know there is at least one character | 2379 // character. At this point we know there is at least one character |
2355 // in each string, due to the trivial case handling above. | 2380 // in each string, due to the trivial case handling above. |
2356 int d = str1->Get(0) - str2->Get(0); | 2381 int d = str1->Get(0) - str2->Get(0); |
2357 if (d != 0) return Smi::FromInt(d); | 2382 if (d != 0) return Smi::FromInt(d); |
2358 | 2383 |
2359 str1->TryFlattenIfNotFlat(); | 2384 str1->TryFlattenIfNotFlat(); |
2360 str2->TryFlattenIfNotFlat(); | 2385 str2->TryFlattenIfNotFlat(); |
2361 | 2386 |
2362 static StringInputBuffer buf1; | 2387 RuntimeData* data = v8_context()->runtime_data_; |
2363 static StringInputBuffer buf2; | 2388 StringInputBuffer& buf1 = data->buf1_; |
| 2389 StringInputBuffer& buf2 = data->buf2_; |
2364 | 2390 |
2365 buf1.Reset(str1); | 2391 buf1.Reset(str1); |
2366 buf2.Reset(str2); | 2392 buf2.Reset(str2); |
2367 | 2393 |
2368 for (int i = 0; i < end; i++) { | 2394 for (int i = 0; i < end; i++) { |
2369 uint16_t char1 = buf1.GetNext(); | 2395 uint16_t char1 = buf1.GetNext(); |
2370 uint16_t char2 = buf2.GetNext(); | 2396 uint16_t char2 = buf2.GetNext(); |
2371 if (char1 != char2) return Smi::FromInt(char1 - char2); | 2397 if (char1 != char2) return Smi::FromInt(char1 - char2); |
2372 } | 2398 } |
2373 | 2399 |
(...skipping 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3267 const char hex_chars[] = "0123456789ABCDEF"; | 3293 const char hex_chars[] = "0123456789ABCDEF"; |
3268 NoHandleAllocation ha; | 3294 NoHandleAllocation ha; |
3269 ASSERT(args.length() == 1); | 3295 ASSERT(args.length() == 1); |
3270 CONVERT_CHECKED(String, source, args[0]); | 3296 CONVERT_CHECKED(String, source, args[0]); |
3271 | 3297 |
3272 source->TryFlattenIfNotFlat(); | 3298 source->TryFlattenIfNotFlat(); |
3273 | 3299 |
3274 int escaped_length = 0; | 3300 int escaped_length = 0; |
3275 int length = source->length(); | 3301 int length = source->length(); |
3276 { | 3302 { |
3277 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 3303 Access<StringInputBuffer> buffer( |
| 3304 &v8_context()->runtime_data_->runtime_string_input_buffer_); |
3278 buffer->Reset(source); | 3305 buffer->Reset(source); |
3279 while (buffer->has_more()) { | 3306 while (buffer->has_more()) { |
3280 uint16_t character = buffer->GetNext(); | 3307 uint16_t character = buffer->GetNext(); |
3281 if (character >= 256) { | 3308 if (character >= 256) { |
3282 escaped_length += 6; | 3309 escaped_length += 6; |
3283 } else if (IsNotEscaped(character)) { | 3310 } else if (IsNotEscaped(character)) { |
3284 escaped_length++; | 3311 escaped_length++; |
3285 } else { | 3312 } else { |
3286 escaped_length += 3; | 3313 escaped_length += 3; |
3287 } | 3314 } |
3288 // We don't allow strings that are longer than a maximal length. | 3315 // We don't allow strings that are longer than a maximal length. |
3289 if (escaped_length > String::kMaxLength) { | 3316 if (escaped_length > String::kMaxLength) { |
3290 Top::context()->mark_out_of_memory(); | 3317 Top::context()->mark_out_of_memory(); |
3291 return Failure::OutOfMemoryException(); | 3318 return Failure::OutOfMemoryException(); |
3292 } | 3319 } |
3293 } | 3320 } |
3294 } | 3321 } |
3295 // No length change implies no change. Return original string if no change. | 3322 // No length change implies no change. Return original string if no change. |
3296 if (escaped_length == length) { | 3323 if (escaped_length == length) { |
3297 return source; | 3324 return source; |
3298 } | 3325 } |
3299 Object* o = Heap::AllocateRawAsciiString(escaped_length); | 3326 Object* o = Heap::AllocateRawAsciiString(escaped_length); |
3300 if (o->IsFailure()) return o; | 3327 if (o->IsFailure()) return o; |
3301 String* destination = String::cast(o); | 3328 String* destination = String::cast(o); |
3302 int dest_position = 0; | 3329 int dest_position = 0; |
3303 | 3330 |
3304 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 3331 Access<StringInputBuffer> buffer( |
| 3332 &v8_context()->runtime_data_->runtime_string_input_buffer_); |
3305 buffer->Rewind(); | 3333 buffer->Rewind(); |
3306 while (buffer->has_more()) { | 3334 while (buffer->has_more()) { |
3307 uint16_t chr = buffer->GetNext(); | 3335 uint16_t chr = buffer->GetNext(); |
3308 if (chr >= 256) { | 3336 if (chr >= 256) { |
3309 destination->Set(dest_position, '%'); | 3337 destination->Set(dest_position, '%'); |
3310 destination->Set(dest_position+1, 'u'); | 3338 destination->Set(dest_position+1, 'u'); |
3311 destination->Set(dest_position+2, hex_chars[chr >> 12]); | 3339 destination->Set(dest_position+2, hex_chars[chr >> 12]); |
3312 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); | 3340 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
3313 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); | 3341 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
3314 destination->Set(dest_position+5, hex_chars[chr & 0xf]); | 3342 destination->Set(dest_position+5, hex_chars[chr & 0xf]); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3420 | 3448 |
3421 CONVERT_CHECKED(String, s, args[0]); | 3449 CONVERT_CHECKED(String, s, args[0]); |
3422 CONVERT_SMI_CHECKED(radix, args[1]); | 3450 CONVERT_SMI_CHECKED(radix, args[1]); |
3423 | 3451 |
3424 s->TryFlattenIfNotFlat(); | 3452 s->TryFlattenIfNotFlat(); |
3425 | 3453 |
3426 int len = s->length(); | 3454 int len = s->length(); |
3427 int i; | 3455 int i; |
3428 | 3456 |
3429 // Skip leading white space. | 3457 // Skip leading white space. |
3430 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; | 3458 unibrow::Predicate<unibrow::WhiteSpace, 128>& kIsWhiteSpace = |
| 3459 v8_context()->scanner_data_.kIsWhiteSpace_; |
| 3460 for (i = 0; i < len && kIsWhiteSpace.get(s->Get(i)); i++) ; |
3431 if (i == len) return Heap::nan_value(); | 3461 if (i == len) return Heap::nan_value(); |
3432 | 3462 |
3433 // Compute the sign (default to +). | 3463 // Compute the sign (default to +). |
3434 int sign = 1; | 3464 int sign = 1; |
3435 if (s->Get(i) == '-') { | 3465 if (s->Get(i) == '-') { |
3436 sign = -1; | 3466 sign = -1; |
3437 i++; | 3467 i++; |
3438 } else if (s->Get(i) == '+') { | 3468 } else if (s->Get(i) == '+') { |
3439 i++; | 3469 i++; |
3440 } | 3470 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3475 CONVERT_CHECKED(String, str, args[0]); | 3505 CONVERT_CHECKED(String, str, args[0]); |
3476 | 3506 |
3477 // ECMA-262 section 15.1.2.3, empty string is NaN | 3507 // ECMA-262 section 15.1.2.3, empty string is NaN |
3478 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value()); | 3508 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value()); |
3479 | 3509 |
3480 // Create a number object from the value. | 3510 // Create a number object from the value. |
3481 return Heap::NumberFromDouble(value); | 3511 return Heap::NumberFromDouble(value); |
3482 } | 3512 } |
3483 | 3513 |
3484 | 3514 |
3485 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; | |
3486 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; | |
3487 | 3515 |
3488 | 3516 |
3489 template <class Converter> | 3517 template <class Converter> |
3490 static Object* ConvertCaseHelper(String* s, | 3518 static Object* ConvertCaseHelper(String* s, |
3491 int length, | 3519 int length, |
3492 int input_string_length, | 3520 int input_string_length, |
3493 unibrow::Mapping<Converter, 128>* mapping) { | 3521 unibrow::Mapping<Converter, 128>* mapping) { |
3494 // We try this twice, once with the assumption that the result is no longer | 3522 // We try this twice, once with the assumption that the result is no longer |
3495 // than the input and, if that assumption breaks, again with the exact | 3523 // than the input and, if that assumption breaks, again with the exact |
3496 // length. This may not be pretty, but it is nicer than what was here before | 3524 // length. This may not be pretty, but it is nicer than what was here before |
3497 // and I hereby claim my vaffel-is. | 3525 // and I hereby claim my vaffel-is. |
3498 // | 3526 // |
3499 // Allocate the resulting string. | 3527 // Allocate the resulting string. |
3500 // | 3528 // |
3501 // NOTE: This assumes that the upper/lower case of an ascii | 3529 // NOTE: This assumes that the upper/lower case of an ascii |
3502 // character is also ascii. This is currently the case, but it | 3530 // character is also ascii. This is currently the case, but it |
3503 // might break in the future if we implement more context and locale | 3531 // might break in the future if we implement more context and locale |
3504 // dependent upper/lower conversions. | 3532 // dependent upper/lower conversions. |
3505 Object* o = s->IsAsciiRepresentation() | 3533 Object* o = s->IsAsciiRepresentation() |
3506 ? Heap::AllocateRawAsciiString(length) | 3534 ? Heap::AllocateRawAsciiString(length) |
3507 : Heap::AllocateRawTwoByteString(length); | 3535 : Heap::AllocateRawTwoByteString(length); |
3508 if (o->IsFailure()) return o; | 3536 if (o->IsFailure()) return o; |
3509 String* result = String::cast(o); | 3537 String* result = String::cast(o); |
3510 bool has_changed_character = false; | 3538 bool has_changed_character = false; |
3511 | 3539 |
3512 // Convert all characters to upper case, assuming that they will fit | 3540 // Convert all characters to upper case, assuming that they will fit |
3513 // in the buffer | 3541 // in the buffer |
3514 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 3542 Access<StringInputBuffer> buffer(&v8_context()->runtime_data_-> |
| 3543 runtime_string_input_buffer_); |
3515 buffer->Reset(s); | 3544 buffer->Reset(s); |
3516 unibrow::uchar chars[Converter::kMaxWidth]; | 3545 unibrow::uchar chars[Converter::kMaxWidth]; |
3517 // We can assume that the string is not empty | 3546 // We can assume that the string is not empty |
3518 uc32 current = buffer->GetNext(); | 3547 uc32 current = buffer->GetNext(); |
3519 for (int i = 0; i < length;) { | 3548 for (int i = 0; i < length;) { |
3520 bool has_next = buffer->has_more(); | 3549 bool has_next = buffer->has_more(); |
3521 uc32 next = has_next ? buffer->GetNext() : 0; | 3550 uc32 next = has_next ? buffer->GetNext() : 0; |
3522 int char_length = mapping->get(current, next, chars); | 3551 int char_length = mapping->get(current, next, chars); |
3523 if (char_length == 0) { | 3552 if (char_length == 0) { |
3524 // The case conversion of this character is the character itself. | 3553 // The case conversion of this character is the character itself. |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3601 Object* answer = ConvertCaseHelper(s, length, length, mapping); | 3630 Object* answer = ConvertCaseHelper(s, length, length, mapping); |
3602 if (answer->IsSmi()) { | 3631 if (answer->IsSmi()) { |
3603 // Retry with correct length. | 3632 // Retry with correct length. |
3604 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); | 3633 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); |
3605 } | 3634 } |
3606 return answer; // This may be a failure. | 3635 return answer; // This may be a failure. |
3607 } | 3636 } |
3608 | 3637 |
3609 | 3638 |
3610 static Object* Runtime_StringToLowerCase(Arguments args) { | 3639 static Object* Runtime_StringToLowerCase(Arguments args) { |
3611 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); | 3640 return ConvertCase<unibrow::ToLowercase>( |
| 3641 args, |
| 3642 &v8_context()->runtime_data_->to_lower_mapping_); |
3612 } | 3643 } |
3613 | 3644 |
3614 | 3645 |
3615 static Object* Runtime_StringToUpperCase(Arguments args) { | 3646 static Object* Runtime_StringToUpperCase(Arguments args) { |
3616 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); | 3647 return ConvertCase<unibrow::ToUppercase>( |
| 3648 args, |
| 3649 &v8_context()->runtime_data_->to_upper_mapping_); |
3617 } | 3650 } |
3618 | 3651 |
3619 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { | 3652 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { |
3620 return unibrow::WhiteSpace::Is(c) || c == 0x200b; | 3653 return unibrow::WhiteSpace::Is(c) || c == 0x200b; |
3621 } | 3654 } |
3622 | 3655 |
3623 static Object* Runtime_StringTrim(Arguments args) { | 3656 static Object* Runtime_StringTrim(Arguments args) { |
3624 NoHandleAllocation ha; | 3657 NoHandleAllocation ha; |
3625 ASSERT(args.length() == 3); | 3658 ASSERT(args.length() == 3); |
3626 | 3659 |
(...skipping 15 matching lines...) Expand all Loading... |
3642 if (trimRight) { | 3675 if (trimRight) { |
3643 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { | 3676 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { |
3644 right--; | 3677 right--; |
3645 } | 3678 } |
3646 } | 3679 } |
3647 return s->SubString(left, right); | 3680 return s->SubString(left, right); |
3648 } | 3681 } |
3649 | 3682 |
3650 bool Runtime::IsUpperCaseChar(uint16_t ch) { | 3683 bool Runtime::IsUpperCaseChar(uint16_t ch) { |
3651 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; | 3684 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; |
3652 int char_length = to_upper_mapping.get(ch, 0, chars); | 3685 int char_length = v8_context()->runtime_data_-> |
| 3686 to_upper_mapping_.get(ch, 0, chars); |
3653 return char_length == 0; | 3687 return char_length == 0; |
3654 } | 3688 } |
3655 | 3689 |
3656 | 3690 |
3657 static Object* Runtime_NumberToString(Arguments args) { | 3691 static Object* Runtime_NumberToString(Arguments args) { |
3658 NoHandleAllocation ha; | 3692 NoHandleAllocation ha; |
3659 ASSERT(args.length() == 1); | 3693 ASSERT(args.length() == 1); |
3660 | 3694 |
3661 Object* number = args[0]; | 3695 Object* number = args[0]; |
3662 RUNTIME_ASSERT(number->IsNumber()); | 3696 RUNTIME_ASSERT(number->IsNumber()); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3779 // NewNumberFromDouble may return a Smi instead of a Number object | 3813 // NewNumberFromDouble may return a Smi instead of a Number object |
3780 return Heap::NewNumberFromDouble(x); | 3814 return Heap::NewNumberFromDouble(x); |
3781 } | 3815 } |
3782 | 3816 |
3783 | 3817 |
3784 static Object* Runtime_StringAdd(Arguments args) { | 3818 static Object* Runtime_StringAdd(Arguments args) { |
3785 NoHandleAllocation ha; | 3819 NoHandleAllocation ha; |
3786 ASSERT(args.length() == 2); | 3820 ASSERT(args.length() == 2); |
3787 CONVERT_CHECKED(String, str1, args[0]); | 3821 CONVERT_CHECKED(String, str1, args[0]); |
3788 CONVERT_CHECKED(String, str2, args[1]); | 3822 CONVERT_CHECKED(String, str2, args[1]); |
3789 Counters::string_add_runtime.Increment(); | 3823 INC_COUNTER(string_add_runtime); |
3790 return Heap::AllocateConsString(str1, str2); | 3824 return Heap::AllocateConsString(str1, str2); |
3791 } | 3825 } |
3792 | 3826 |
3793 | 3827 |
3794 template<typename sinkchar> | 3828 template<typename sinkchar> |
3795 static inline void StringBuilderConcatHelper(String* special, | 3829 static inline void StringBuilderConcatHelper(String* special, |
3796 sinkchar* sink, | 3830 sinkchar* sink, |
3797 FixedArray* fixed_array, | 3831 FixedArray* fixed_array, |
3798 int array_length) { | 3832 int array_length) { |
3799 int position = 0; | 3833 int position = 0; |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4048 return Smi::FromInt(GREATER); | 4082 return Smi::FromInt(GREATER); |
4049 } | 4083 } |
4050 | 4084 |
4051 | 4085 |
4052 // Compare two Smis as if they were converted to strings and then | 4086 // Compare two Smis as if they were converted to strings and then |
4053 // compared lexicographically. | 4087 // compared lexicographically. |
4054 static Object* Runtime_SmiLexicographicCompare(Arguments args) { | 4088 static Object* Runtime_SmiLexicographicCompare(Arguments args) { |
4055 NoHandleAllocation ha; | 4089 NoHandleAllocation ha; |
4056 ASSERT(args.length() == 2); | 4090 ASSERT(args.length() == 2); |
4057 | 4091 |
| 4092 RuntimeData* const data = v8_context()->runtime_data_; |
4058 // Arrays for the individual characters of the two Smis. Smis are | 4093 // Arrays for the individual characters of the two Smis. Smis are |
4059 // 31 bit integers and 10 decimal digits are therefore enough. | 4094 // 31 bit integers and 10 decimal digits are therefore enough. |
4060 static int x_elms[10]; | 4095 int * const x_elms = data->x_elms_; |
4061 static int y_elms[10]; | 4096 int * const y_elms = data->y_elms_; |
4062 | 4097 |
4063 // Extract the integer values from the Smis. | 4098 // Extract the integer values from the Smis. |
4064 CONVERT_CHECKED(Smi, x, args[0]); | 4099 CONVERT_CHECKED(Smi, x, args[0]); |
4065 CONVERT_CHECKED(Smi, y, args[1]); | 4100 CONVERT_CHECKED(Smi, y, args[1]); |
4066 int x_value = x->value(); | 4101 int x_value = x->value(); |
4067 int y_value = y->value(); | 4102 int y_value = y->value(); |
4068 | 4103 |
4069 // If the integers are equal so are the string representations. | 4104 // If the integers are equal so are the string representations. |
4070 if (x_value == y_value) return Smi::FromInt(EQUAL); | 4105 if (x_value == y_value) return Smi::FromInt(EQUAL); |
4071 | 4106 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4125 return Smi::FromInt(LESS); | 4160 return Smi::FromInt(LESS); |
4126 } | 4161 } |
4127 | 4162 |
4128 int d = x->Get(0) - y->Get(0); | 4163 int d = x->Get(0) - y->Get(0); |
4129 if (d < 0) return Smi::FromInt(LESS); | 4164 if (d < 0) return Smi::FromInt(LESS); |
4130 else if (d > 0) return Smi::FromInt(GREATER); | 4165 else if (d > 0) return Smi::FromInt(GREATER); |
4131 | 4166 |
4132 x->TryFlattenIfNotFlat(); | 4167 x->TryFlattenIfNotFlat(); |
4133 y->TryFlattenIfNotFlat(); | 4168 y->TryFlattenIfNotFlat(); |
4134 | 4169 |
4135 static StringInputBuffer bufx; | 4170 RuntimeData* const data = v8_context()->runtime_data_; |
4136 static StringInputBuffer bufy; | 4171 StringInputBuffer& bufx = data->bufx_; |
| 4172 StringInputBuffer& bufy = data->bufy_; |
4137 bufx.Reset(x); | 4173 bufx.Reset(x); |
4138 bufy.Reset(y); | 4174 bufy.Reset(y); |
4139 while (bufx.has_more() && bufy.has_more()) { | 4175 while (bufx.has_more() && bufy.has_more()) { |
4140 int d = bufx.GetNext() - bufy.GetNext(); | 4176 int d = bufx.GetNext() - bufy.GetNext(); |
4141 if (d < 0) return Smi::FromInt(LESS); | 4177 if (d < 0) return Smi::FromInt(LESS); |
4142 else if (d > 0) return Smi::FromInt(GREATER); | 4178 else if (d > 0) return Smi::FromInt(GREATER); |
4143 } | 4179 } |
4144 | 4180 |
4145 // x is (non-trivial) prefix of y: | 4181 // x is (non-trivial) prefix of y: |
4146 if (bufy.has_more()) return Smi::FromInt(LESS); | 4182 if (bufy.has_more()) return Smi::FromInt(LESS); |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4498 | 4534 |
4499 bool first_allocation = !function->has_initial_map(); | 4535 bool first_allocation = !function->has_initial_map(); |
4500 Handle<JSObject> result = Factory::NewJSObject(function); | 4536 Handle<JSObject> result = Factory::NewJSObject(function); |
4501 if (first_allocation) { | 4537 if (first_allocation) { |
4502 Handle<Map> map = Handle<Map>(function->initial_map()); | 4538 Handle<Map> map = Handle<Map>(function->initial_map()); |
4503 Handle<Code> stub = Handle<Code>( | 4539 Handle<Code> stub = Handle<Code>( |
4504 ComputeConstructStub(Handle<SharedFunctionInfo>(function->shared()))); | 4540 ComputeConstructStub(Handle<SharedFunctionInfo>(function->shared()))); |
4505 function->shared()->set_construct_stub(*stub); | 4541 function->shared()->set_construct_stub(*stub); |
4506 } | 4542 } |
4507 | 4543 |
4508 Counters::constructed_objects.Increment(); | 4544 INC_COUNTER(constructed_objects); |
4509 Counters::constructed_objects_runtime.Increment(); | 4545 INC_COUNTER(constructed_objects_runtime); |
4510 | 4546 |
4511 return *result; | 4547 return *result; |
4512 } | 4548 } |
4513 | 4549 |
4514 | 4550 |
4515 static Object* Runtime_LazyCompile(Arguments args) { | 4551 static Object* Runtime_LazyCompile(Arguments args) { |
4516 HandleScope scope; | 4552 HandleScope scope; |
4517 ASSERT(args.length() == 1); | 4553 ASSERT(args.length() == 1); |
4518 | 4554 |
4519 Handle<JSFunction> function = args.at<JSFunction>(0); | 4555 Handle<JSFunction> function = args.at<JSFunction>(0); |
(...skipping 3435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7955 | 7991 |
7956 void Runtime::PerformGC(Object* result) { | 7992 void Runtime::PerformGC(Object* result) { |
7957 Failure* failure = Failure::cast(result); | 7993 Failure* failure = Failure::cast(result); |
7958 if (failure->IsRetryAfterGC()) { | 7994 if (failure->IsRetryAfterGC()) { |
7959 // Try to do a garbage collection; ignore it if it fails. The C | 7995 // Try to do a garbage collection; ignore it if it fails. The C |
7960 // entry stub will throw an out-of-memory exception in that case. | 7996 // entry stub will throw an out-of-memory exception in that case. |
7961 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); | 7997 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); |
7962 } else { | 7998 } else { |
7963 // Handle last resort GC and make sure to allow future allocations | 7999 // Handle last resort GC and make sure to allow future allocations |
7964 // to grow the heap without causing GCs (if possible). | 8000 // to grow the heap without causing GCs (if possible). |
7965 Counters::gc_last_resort_from_js.Increment(); | 8001 INC_COUNTER(gc_last_resort_from_js); |
7966 Heap::CollectAllGarbage(false); | 8002 Heap::CollectAllGarbage(false); |
7967 } | 8003 } |
7968 } | 8004 } |
7969 | 8005 |
| 8006 void Runtime::PostConstruct() { |
| 8007 v8_context()->runtime_data_ = new RuntimeData(); |
| 8008 } |
| 8009 |
| 8010 void Runtime::PreDestroy() { |
| 8011 delete v8_context()->runtime_data_; |
| 8012 v8_context()->runtime_data_ = NULL; |
| 8013 } |
7970 | 8014 |
7971 } } // namespace v8::internal | 8015 } } // namespace v8::internal |
OLD | NEW |