| 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 |