OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 3471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3482 | 3482 |
3483 // No need to flatten if we are going to find the answer on the first | 3483 // No need to flatten if we are going to find the answer on the first |
3484 // character. At this point we know there is at least one character | 3484 // character. At this point we know there is at least one character |
3485 // in each string, due to the trivial case handling above. | 3485 // in each string, due to the trivial case handling above. |
3486 int d = str1->Get(0) - str2->Get(0); | 3486 int d = str1->Get(0) - str2->Get(0); |
3487 if (d != 0) return Smi::FromInt(d); | 3487 if (d != 0) return Smi::FromInt(d); |
3488 | 3488 |
3489 str1->TryFlatten(); | 3489 str1->TryFlatten(); |
3490 str2->TryFlatten(); | 3490 str2->TryFlatten(); |
3491 | 3491 |
3492 StringInputBuffer& buf1 = | 3492 ConsStringIteratorOp* op1 = |
3493 *isolate->runtime_state()->string_locale_compare_buf1(); | 3493 isolate->runtime_state()->string_locale_compare_it1(); |
3494 StringInputBuffer& buf2 = | 3494 ConsStringIteratorOp* op2 = |
3495 *isolate->runtime_state()->string_locale_compare_buf2(); | 3495 isolate->runtime_state()->string_locale_compare_it2(); |
3496 | 3496 // TODO(dcarney) Can do array compares here more efficiently. |
3497 buf1.Reset(str1); | 3497 StringCharacterStream stream1(str1, op1); |
3498 buf2.Reset(str2); | 3498 StringCharacterStream stream2(str2, op2); |
3499 | 3499 |
3500 for (int i = 0; i < end; i++) { | 3500 for (int i = 0; i < end; i++) { |
3501 uint16_t char1 = buf1.GetNext(); | 3501 uint16_t char1 = stream1.GetNext(); |
3502 uint16_t char2 = buf2.GetNext(); | 3502 uint16_t char2 = stream2.GetNext(); |
3503 if (char1 != char2) return Smi::FromInt(char1 - char2); | 3503 if (char1 != char2) return Smi::FromInt(char1 - char2); |
3504 } | 3504 } |
3505 | 3505 |
3506 return Smi::FromInt(str1_length - str2_length); | 3506 return Smi::FromInt(str1_length - str2_length); |
3507 } | 3507 } |
3508 | 3508 |
3509 | 3509 |
3510 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { | 3510 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { |
3511 NoHandleAllocation ha; | 3511 NoHandleAllocation ha; |
3512 ASSERT(args.length() == 3); | 3512 ASSERT(args.length() == 3); |
(...skipping 1623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5136 const char hex_chars[] = "0123456789ABCDEF"; | 5136 const char hex_chars[] = "0123456789ABCDEF"; |
5137 NoHandleAllocation ha; | 5137 NoHandleAllocation ha; |
5138 ASSERT(args.length() == 1); | 5138 ASSERT(args.length() == 1); |
5139 CONVERT_ARG_CHECKED(String, source, 0); | 5139 CONVERT_ARG_CHECKED(String, source, 0); |
5140 | 5140 |
5141 source->TryFlatten(); | 5141 source->TryFlatten(); |
5142 | 5142 |
5143 int escaped_length = 0; | 5143 int escaped_length = 0; |
5144 int length = source->length(); | 5144 int length = source->length(); |
5145 { | 5145 { |
5146 Access<StringInputBuffer> buffer( | 5146 Access<ConsStringIteratorOp> op( |
5147 isolate->runtime_state()->string_input_buffer()); | 5147 isolate->runtime_state()->string_iterator()); |
5148 buffer->Reset(source); | 5148 StringCharacterStream stream(source, op.value()); |
5149 while (buffer->has_more()) { | 5149 while (stream.HasMore()) { |
5150 uint16_t character = buffer->GetNext(); | 5150 uint16_t character = stream.GetNext(); |
5151 if (character >= 256) { | 5151 if (character >= 256) { |
5152 escaped_length += 6; | 5152 escaped_length += 6; |
5153 } else if (IsNotEscaped(character)) { | 5153 } else if (IsNotEscaped(character)) { |
5154 escaped_length++; | 5154 escaped_length++; |
5155 } else { | 5155 } else { |
5156 escaped_length += 3; | 5156 escaped_length += 3; |
5157 } | 5157 } |
5158 // We don't allow strings that are longer than a maximal length. | 5158 // We don't allow strings that are longer than a maximal length. |
5159 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow. | 5159 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow. |
5160 if (escaped_length > String::kMaxLength) { | 5160 if (escaped_length > String::kMaxLength) { |
5161 isolate->context()->mark_out_of_memory(); | 5161 isolate->context()->mark_out_of_memory(); |
5162 return Failure::OutOfMemoryException(); | 5162 return Failure::OutOfMemoryException(); |
5163 } | 5163 } |
5164 } | 5164 } |
5165 } | 5165 } |
5166 // No length change implies no change. Return original string if no change. | 5166 // No length change implies no change. Return original string if no change. |
5167 if (escaped_length == length) { | 5167 if (escaped_length == length) { |
5168 return source; | 5168 return source; |
5169 } | 5169 } |
5170 Object* o; | 5170 Object* o; |
5171 { MaybeObject* maybe_o = | 5171 { MaybeObject* maybe_o = |
5172 isolate->heap()->AllocateRawOneByteString(escaped_length); | 5172 isolate->heap()->AllocateRawOneByteString(escaped_length); |
5173 if (!maybe_o->ToObject(&o)) return maybe_o; | 5173 if (!maybe_o->ToObject(&o)) return maybe_o; |
5174 } | 5174 } |
5175 String* destination = String::cast(o); | 5175 String* destination = String::cast(o); |
5176 int dest_position = 0; | 5176 int dest_position = 0; |
5177 | 5177 |
5178 Access<StringInputBuffer> buffer( | 5178 Access<ConsStringIteratorOp> op( |
5179 isolate->runtime_state()->string_input_buffer()); | 5179 isolate->runtime_state()->string_iterator()); |
5180 buffer->Rewind(); | 5180 StringCharacterStream stream(source, op.value()); |
5181 while (buffer->has_more()) { | 5181 while (stream.HasMore()) { |
5182 uint16_t chr = buffer->GetNext(); | 5182 uint16_t chr = stream.GetNext(); |
5183 if (chr >= 256) { | 5183 if (chr >= 256) { |
5184 destination->Set(dest_position, '%'); | 5184 destination->Set(dest_position, '%'); |
5185 destination->Set(dest_position+1, 'u'); | 5185 destination->Set(dest_position+1, 'u'); |
5186 destination->Set(dest_position+2, hex_chars[chr >> 12]); | 5186 destination->Set(dest_position+2, hex_chars[chr >> 12]); |
5187 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); | 5187 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
5188 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); | 5188 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
5189 destination->Set(dest_position+5, hex_chars[chr & 0xf]); | 5189 destination->Set(dest_position+5, hex_chars[chr & 0xf]); |
5190 dest_position += 6; | 5190 dest_position += 6; |
5191 } else if (IsNotEscaped(chr)) { | 5191 } else if (IsNotEscaped(chr)) { |
5192 destination->Set(dest_position, chr); | 5192 destination->Set(dest_position, chr); |
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5710 { MaybeObject* maybe_o = s->IsOneByteRepresentation() | 5710 { MaybeObject* maybe_o = s->IsOneByteRepresentation() |
5711 ? isolate->heap()->AllocateRawOneByteString(length) | 5711 ? isolate->heap()->AllocateRawOneByteString(length) |
5712 : isolate->heap()->AllocateRawTwoByteString(length); | 5712 : isolate->heap()->AllocateRawTwoByteString(length); |
5713 if (!maybe_o->ToObject(&o)) return maybe_o; | 5713 if (!maybe_o->ToObject(&o)) return maybe_o; |
5714 } | 5714 } |
5715 String* result = String::cast(o); | 5715 String* result = String::cast(o); |
5716 bool has_changed_character = false; | 5716 bool has_changed_character = false; |
5717 | 5717 |
5718 // Convert all characters to upper case, assuming that they will fit | 5718 // Convert all characters to upper case, assuming that they will fit |
5719 // in the buffer | 5719 // in the buffer |
5720 Access<StringInputBuffer> buffer( | 5720 Access<ConsStringIteratorOp> op( |
5721 isolate->runtime_state()->string_input_buffer()); | 5721 isolate->runtime_state()->string_iterator()); |
5722 buffer->Reset(s); | 5722 StringCharacterStream stream(s, op.value()); |
5723 unibrow::uchar chars[Converter::kMaxWidth]; | 5723 unibrow::uchar chars[Converter::kMaxWidth]; |
5724 // We can assume that the string is not empty | 5724 // We can assume that the string is not empty |
5725 uc32 current = buffer->GetNext(); | 5725 uc32 current = stream.GetNext(); |
5726 for (int i = 0; i < length;) { | 5726 for (int i = 0; i < length;) { |
5727 bool has_next = buffer->has_more(); | 5727 bool has_next = stream.HasMore(); |
5728 uc32 next = has_next ? buffer->GetNext() : 0; | 5728 uc32 next = has_next ? stream.GetNext() : 0; |
5729 int char_length = mapping->get(current, next, chars); | 5729 int char_length = mapping->get(current, next, chars); |
5730 if (char_length == 0) { | 5730 if (char_length == 0) { |
5731 // The case conversion of this character is the character itself. | 5731 // The case conversion of this character is the character itself. |
5732 result->Set(i, current); | 5732 result->Set(i, current); |
5733 i++; | 5733 i++; |
5734 } else if (char_length == 1) { | 5734 } else if (char_length == 1) { |
5735 // Common case: converting the letter resulted in one character. | 5735 // Common case: converting the letter resulted in one character. |
5736 ASSERT(static_cast<uc32>(chars[0]) != current); | 5736 ASSERT(static_cast<uc32>(chars[0]) != current); |
5737 result->Set(i, chars[0]); | 5737 result->Set(i, chars[0]); |
5738 has_changed_character = true; | 5738 has_changed_character = true; |
5739 i++; | 5739 i++; |
5740 } else if (length == input_string_length) { | 5740 } else if (length == input_string_length) { |
5741 // We've assumed that the result would be as long as the | 5741 // We've assumed that the result would be as long as the |
5742 // input but here is a character that converts to several | 5742 // input but here is a character that converts to several |
5743 // characters. No matter, we calculate the exact length | 5743 // characters. No matter, we calculate the exact length |
5744 // of the result and try the whole thing again. | 5744 // of the result and try the whole thing again. |
5745 // | 5745 // |
5746 // Note that this leaves room for optimization. We could just | 5746 // Note that this leaves room for optimization. We could just |
5747 // memcpy what we already have to the result string. Also, | 5747 // memcpy what we already have to the result string. Also, |
5748 // the result string is the last object allocated we could | 5748 // the result string is the last object allocated we could |
5749 // "realloc" it and probably, in the vast majority of cases, | 5749 // "realloc" it and probably, in the vast majority of cases, |
5750 // extend the existing string to be able to hold the full | 5750 // extend the existing string to be able to hold the full |
5751 // result. | 5751 // result. |
5752 int next_length = 0; | 5752 int next_length = 0; |
5753 if (has_next) { | 5753 if (has_next) { |
5754 next_length = mapping->get(next, 0, chars); | 5754 next_length = mapping->get(next, 0, chars); |
5755 if (next_length == 0) next_length = 1; | 5755 if (next_length == 0) next_length = 1; |
5756 } | 5756 } |
5757 int current_length = i + char_length + next_length; | 5757 int current_length = i + char_length + next_length; |
5758 while (buffer->has_more()) { | 5758 while (stream.HasMore()) { |
5759 current = buffer->GetNext(); | 5759 current = stream.GetNext(); |
5760 // NOTE: we use 0 as the next character here because, while | 5760 // NOTE: we use 0 as the next character here because, while |
5761 // the next character may affect what a character converts to, | 5761 // the next character may affect what a character converts to, |
5762 // it does not in any case affect the length of what it convert | 5762 // it does not in any case affect the length of what it convert |
5763 // to. | 5763 // to. |
5764 int char_length = mapping->get(current, 0, chars); | 5764 int char_length = mapping->get(current, 0, chars); |
5765 if (char_length == 0) char_length = 1; | 5765 if (char_length == 0) char_length = 1; |
5766 current_length += char_length; | 5766 current_length += char_length; |
5767 if (current_length > Smi::kMaxValue) { | 5767 if (current_length > Smi::kMaxValue) { |
5768 isolate->context()->mark_out_of_memory(); | 5768 isolate->context()->mark_out_of_memory(); |
5769 return Failure::OutOfMemoryException(); | 5769 return Failure::OutOfMemoryException(); |
(...skipping 1183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6953 x_scaled /= 10; | 6953 x_scaled /= 10; |
6954 tie = GREATER; | 6954 tie = GREATER; |
6955 } | 6955 } |
6956 | 6956 |
6957 if (x_scaled < y_scaled) return Smi::FromInt(LESS); | 6957 if (x_scaled < y_scaled) return Smi::FromInt(LESS); |
6958 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); | 6958 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); |
6959 return Smi::FromInt(tie); | 6959 return Smi::FromInt(tie); |
6960 } | 6960 } |
6961 | 6961 |
6962 | 6962 |
6963 static Object* StringInputBufferCompare(RuntimeState* state, | 6963 static Object* StringCharacterStreamCompare(RuntimeState* state, |
6964 String* x, | 6964 String* x, |
6965 String* y) { | 6965 String* y) { |
6966 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx(); | 6966 StringCharacterStream stream_x(x, state->string_iterator_compare_x()); |
6967 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy(); | 6967 StringCharacterStream stream_y(y, state->string_iterator_compare_y()); |
6968 bufx.Reset(x); | 6968 while (stream_x.HasMore() && stream_y.HasMore()) { |
6969 bufy.Reset(y); | 6969 int d = stream_x.GetNext() - stream_y.GetNext(); |
6970 while (bufx.has_more() && bufy.has_more()) { | |
6971 int d = bufx.GetNext() - bufy.GetNext(); | |
6972 if (d < 0) return Smi::FromInt(LESS); | 6970 if (d < 0) return Smi::FromInt(LESS); |
6973 else if (d > 0) return Smi::FromInt(GREATER); | 6971 else if (d > 0) return Smi::FromInt(GREATER); |
6974 } | 6972 } |
6975 | 6973 |
6976 // x is (non-trivial) prefix of y: | 6974 // x is (non-trivial) prefix of y: |
6977 if (bufy.has_more()) return Smi::FromInt(LESS); | 6975 if (stream_y.HasMore()) return Smi::FromInt(LESS); |
6978 // y is prefix of x: | 6976 // y is prefix of x: |
6979 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); | 6977 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL); |
6980 } | 6978 } |
6981 | 6979 |
6982 | 6980 |
6983 static Object* FlatStringCompare(String* x, String* y) { | 6981 static Object* FlatStringCompare(String* x, String* y) { |
6984 ASSERT(x->IsFlat()); | 6982 ASSERT(x->IsFlat()); |
6985 ASSERT(y->IsFlat()); | 6983 ASSERT(y->IsFlat()); |
6986 Object* equal_prefix_result = Smi::FromInt(EQUAL); | 6984 Object* equal_prefix_result = Smi::FromInt(EQUAL); |
6987 int prefix_length = x->length(); | 6985 int prefix_length = x->length(); |
6988 if (y->length() < prefix_length) { | 6986 if (y->length() < prefix_length) { |
6989 prefix_length = y->length(); | 6987 prefix_length = y->length(); |
(...skipping 23 matching lines...) Expand all Loading... |
7013 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 7011 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
7014 } | 7012 } |
7015 } | 7013 } |
7016 Object* result; | 7014 Object* result; |
7017 if (r == 0) { | 7015 if (r == 0) { |
7018 result = equal_prefix_result; | 7016 result = equal_prefix_result; |
7019 } else { | 7017 } else { |
7020 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); | 7018 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); |
7021 } | 7019 } |
7022 ASSERT(result == | 7020 ASSERT(result == |
7023 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y)); | 7021 StringCharacterStreamCompare(Isolate::Current()->runtime_state(), x, y)); |
7024 return result; | 7022 return result; |
7025 } | 7023 } |
7026 | 7024 |
7027 | 7025 |
7028 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { | 7026 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { |
7029 NoHandleAllocation ha; | 7027 NoHandleAllocation ha; |
7030 ASSERT(args.length() == 2); | 7028 ASSERT(args.length() == 2); |
7031 | 7029 |
7032 CONVERT_ARG_CHECKED(String, x, 0); | 7030 CONVERT_ARG_CHECKED(String, x, 0); |
7033 CONVERT_ARG_CHECKED(String, y, 1); | 7031 CONVERT_ARG_CHECKED(String, y, 1); |
(...skipping 15 matching lines...) Expand all Loading... |
7049 | 7047 |
7050 Object* obj; | 7048 Object* obj; |
7051 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); | 7049 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); |
7052 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7050 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7053 } | 7051 } |
7054 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); | 7052 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); |
7055 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7053 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7056 } | 7054 } |
7057 | 7055 |
7058 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) | 7056 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) |
7059 : StringInputBufferCompare(isolate->runtime_state(), x, y); | 7057 : StringCharacterStreamCompare(isolate->runtime_state(), x, y); |
7060 } | 7058 } |
7061 | 7059 |
7062 | 7060 |
7063 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { | 7061 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { |
7064 NoHandleAllocation ha; | 7062 NoHandleAllocation ha; |
7065 ASSERT(args.length() == 1); | 7063 ASSERT(args.length() == 1); |
7066 isolate->counters()->math_acos()->Increment(); | 7064 isolate->counters()->math_acos()->Increment(); |
7067 | 7065 |
7068 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | 7066 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
7069 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); | 7067 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); |
(...skipping 2808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9878 } | 9876 } |
9879 | 9877 |
9880 | 9878 |
9881 // This will not allocate (flatten the string), but it may run | 9879 // This will not allocate (flatten the string), but it may run |
9882 // very slowly for very deeply nested ConsStrings. For debugging use only. | 9880 // very slowly for very deeply nested ConsStrings. For debugging use only. |
9883 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { | 9881 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { |
9884 NoHandleAllocation ha; | 9882 NoHandleAllocation ha; |
9885 ASSERT(args.length() == 1); | 9883 ASSERT(args.length() == 1); |
9886 | 9884 |
9887 CONVERT_ARG_CHECKED(String, string, 0); | 9885 CONVERT_ARG_CHECKED(String, string, 0); |
9888 StringInputBuffer buffer(string); | 9886 ConsStringIteratorOp op; |
9889 while (buffer.has_more()) { | 9887 StringCharacterStream stream(string, &op); |
9890 uint16_t character = buffer.GetNext(); | 9888 while (stream.HasMore()) { |
| 9889 uint16_t character = stream.GetNext(); |
9891 PrintF("%c", character); | 9890 PrintF("%c", character); |
9892 } | 9891 } |
9893 return string; | 9892 return string; |
9894 } | 9893 } |
9895 | 9894 |
9896 // Moves all own elements of an object, that are below a limit, to positions | 9895 // Moves all own elements of an object, that are below a limit, to positions |
9897 // starting at zero. All undefined values are placed after non-undefined values, | 9896 // starting at zero. All undefined values are placed after non-undefined values, |
9898 // and are followed by non-existing element. Does not change the length | 9897 // and are followed by non-existing element. Does not change the length |
9899 // property. | 9898 // property. |
9900 // Returns the number of non-undefined elements collected. | 9899 // Returns the number of non-undefined elements collected. |
(...skipping 3750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13651 // Handle last resort GC and make sure to allow future allocations | 13650 // Handle last resort GC and make sure to allow future allocations |
13652 // to grow the heap without causing GCs (if possible). | 13651 // to grow the heap without causing GCs (if possible). |
13653 isolate->counters()->gc_last_resort_from_js()->Increment(); | 13652 isolate->counters()->gc_last_resort_from_js()->Increment(); |
13654 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 13653 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
13655 "Runtime::PerformGC"); | 13654 "Runtime::PerformGC"); |
13656 } | 13655 } |
13657 } | 13656 } |
13658 | 13657 |
13659 | 13658 |
13660 } } // namespace v8::internal | 13659 } } // namespace v8::internal |
OLD | NEW |