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 1030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 if (len > kMaxShortPrintLength) { | 1041 if (len > kMaxShortPrintLength) { |
1042 accumulator->Add("<Very long string[%u]>", len); | 1042 accumulator->Add("<Very long string[%u]>", len); |
1043 return; | 1043 return; |
1044 } | 1044 } |
1045 | 1045 |
1046 if (!LooksValid()) { | 1046 if (!LooksValid()) { |
1047 accumulator->Add("<Invalid String>"); | 1047 accumulator->Add("<Invalid String>"); |
1048 return; | 1048 return; |
1049 } | 1049 } |
1050 | 1050 |
1051 StringInputBuffer buf(this); | 1051 ConsStringIteratorOp op; |
| 1052 StringCharacterStream stream(this, &op); |
1052 | 1053 |
1053 bool truncated = false; | 1054 bool truncated = false; |
1054 if (len > kMaxShortPrintLength) { | 1055 if (len > kMaxShortPrintLength) { |
1055 len = kMaxShortPrintLength; | 1056 len = kMaxShortPrintLength; |
1056 truncated = true; | 1057 truncated = true; |
1057 } | 1058 } |
1058 bool ascii = true; | 1059 bool ascii = true; |
1059 for (int i = 0; i < len; i++) { | 1060 for (int i = 0; i < len; i++) { |
1060 int c = buf.GetNext(); | 1061 uint16_t c = stream.GetNext(); |
1061 | 1062 |
1062 if (c < 32 || c >= 127) { | 1063 if (c < 32 || c >= 127) { |
1063 ascii = false; | 1064 ascii = false; |
1064 } | 1065 } |
1065 } | 1066 } |
1066 buf.Reset(this); | 1067 stream.Reset(this); |
1067 if (ascii) { | 1068 if (ascii) { |
1068 accumulator->Add("<String[%u]: ", length()); | 1069 accumulator->Add("<String[%u]: ", length()); |
1069 for (int i = 0; i < len; i++) { | 1070 for (int i = 0; i < len; i++) { |
1070 accumulator->Put(buf.GetNext()); | 1071 accumulator->Put(static_cast<char>(stream.GetNext())); |
1071 } | 1072 } |
1072 accumulator->Put('>'); | 1073 accumulator->Put('>'); |
1073 } else { | 1074 } else { |
1074 // Backslash indicates that the string contains control | 1075 // Backslash indicates that the string contains control |
1075 // characters and that backslashes are therefore escaped. | 1076 // characters and that backslashes are therefore escaped. |
1076 accumulator->Add("<String[%u]\\: ", length()); | 1077 accumulator->Add("<String[%u]\\: ", length()); |
1077 for (int i = 0; i < len; i++) { | 1078 for (int i = 0; i < len; i++) { |
1078 int c = buf.GetNext(); | 1079 uint16_t c = stream.GetNext(); |
1079 if (c == '\n') { | 1080 if (c == '\n') { |
1080 accumulator->Add("\\n"); | 1081 accumulator->Add("\\n"); |
1081 } else if (c == '\r') { | 1082 } else if (c == '\r') { |
1082 accumulator->Add("\\r"); | 1083 accumulator->Add("\\r"); |
1083 } else if (c == '\\') { | 1084 } else if (c == '\\') { |
1084 accumulator->Add("\\\\"); | 1085 accumulator->Add("\\\\"); |
1085 } else if (c < 32 || c > 126) { | 1086 } else if (c < 32 || c > 126) { |
1086 accumulator->Add("\\x%02x", c); | 1087 accumulator->Add("\\x%02x", c); |
1087 } else { | 1088 } else { |
1088 accumulator->Put(c); | 1089 accumulator->Put(static_cast<char>(c)); |
1089 } | 1090 } |
1090 } | 1091 } |
1091 if (truncated) { | 1092 if (truncated) { |
1092 accumulator->Put('.'); | 1093 accumulator->Put('.'); |
1093 accumulator->Put('.'); | 1094 accumulator->Put('.'); |
1094 accumulator->Put('.'); | 1095 accumulator->Put('.'); |
1095 } | 1096 } |
1096 accumulator->Put('>'); | 1097 accumulator->Put('>'); |
1097 } | 1098 } |
1098 return; | 1099 return; |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1530 properties()->CopySize(properties()->length() + new_unused + 1); | 1531 properties()->CopySize(properties()->length() + new_unused + 1); |
1531 if (!maybe_values->To(&values)) return maybe_values; | 1532 if (!maybe_values->To(&values)) return maybe_values; |
1532 } | 1533 } |
1533 set_properties(values); | 1534 set_properties(values); |
1534 } | 1535 } |
1535 set_map(new_map); | 1536 set_map(new_map); |
1536 return FastPropertyAtPut(field_index, value); | 1537 return FastPropertyAtPut(field_index, value); |
1537 } | 1538 } |
1538 | 1539 |
1539 | 1540 |
1540 static bool IsIdentifier(UnicodeCache* cache, | 1541 static bool IsIdentifier(UnicodeCache* cache, String* string) { |
1541 unibrow::CharacterStream* buffer) { | |
1542 // Checks whether the buffer contains an identifier (no escape). | 1542 // Checks whether the buffer contains an identifier (no escape). |
1543 if (!buffer->has_more()) return false; | 1543 if (string->length() == 0) return false; |
1544 if (!cache->IsIdentifierStart(buffer->GetNext())) { | 1544 ConsStringIteratorOp op; |
| 1545 StringCharacterStream stream(string, &op); |
| 1546 if (!cache->IsIdentifierStart(stream.GetNext())) { |
1545 return false; | 1547 return false; |
1546 } | 1548 } |
1547 while (buffer->has_more()) { | 1549 while (stream.HasMore()) { |
1548 if (!cache->IsIdentifierPart(buffer->GetNext())) { | 1550 if (!cache->IsIdentifierPart(stream.GetNext())) { |
1549 return false; | 1551 return false; |
1550 } | 1552 } |
1551 } | 1553 } |
1552 return true; | 1554 return true; |
1553 } | 1555 } |
1554 | 1556 |
1555 | 1557 |
1556 MaybeObject* JSObject::AddFastProperty(String* name, | 1558 MaybeObject* JSObject::AddFastProperty(String* name, |
1557 Object* value, | 1559 Object* value, |
1558 PropertyAttributes attributes, | 1560 PropertyAttributes attributes, |
1559 StoreFromKeyed store_mode) { | 1561 StoreFromKeyed store_mode) { |
1560 ASSERT(!IsJSGlobalProxy()); | 1562 ASSERT(!IsJSGlobalProxy()); |
1561 ASSERT(DescriptorArray::kNotFound == | 1563 ASSERT(DescriptorArray::kNotFound == |
1562 map()->instance_descriptors()->Search( | 1564 map()->instance_descriptors()->Search( |
1563 name, map()->NumberOfOwnDescriptors())); | 1565 name, map()->NumberOfOwnDescriptors())); |
1564 | 1566 |
1565 // Normalize the object if the name is an actual string (not the | 1567 // Normalize the object if the name is an actual string (not the |
1566 // hidden symbols) and is not a real identifier. | 1568 // hidden symbols) and is not a real identifier. |
1567 // Normalize the object if it will have too many fast properties. | 1569 // Normalize the object if it will have too many fast properties. |
1568 Isolate* isolate = GetHeap()->isolate(); | 1570 Isolate* isolate = GetHeap()->isolate(); |
1569 StringInputBuffer buffer(name); | 1571 if ((!IsIdentifier(isolate->unicode_cache(), name) |
1570 if ((!IsIdentifier(isolate->unicode_cache(), &buffer) | |
1571 && name != isolate->heap()->hidden_symbol()) || | 1572 && name != isolate->heap()->hidden_symbol()) || |
1572 (map()->unused_property_fields() == 0 && | 1573 (map()->unused_property_fields() == 0 && |
1573 TooManyFastProperties(properties()->length(), store_mode))) { | 1574 TooManyFastProperties(properties()->length(), store_mode))) { |
1574 Object* obj; | 1575 Object* obj; |
1575 MaybeObject* maybe_obj = | 1576 MaybeObject* maybe_obj = |
1576 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 1577 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
1577 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1578 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
1578 | 1579 |
1579 return AddSlowProperty(name, value, attributes); | 1580 return AddSlowProperty(name, value, attributes); |
1580 } | 1581 } |
(...skipping 5006 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6587 int* length_return) { | 6588 int* length_return) { |
6588 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { | 6589 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { |
6589 return SmartArrayPointer<char>(NULL); | 6590 return SmartArrayPointer<char>(NULL); |
6590 } | 6591 } |
6591 Heap* heap = GetHeap(); | 6592 Heap* heap = GetHeap(); |
6592 | 6593 |
6593 // Negative length means the to the end of the string. | 6594 // Negative length means the to the end of the string. |
6594 if (length < 0) length = kMaxInt - offset; | 6595 if (length < 0) length = kMaxInt - offset; |
6595 | 6596 |
6596 // Compute the size of the UTF-8 string. Start at the specified offset. | 6597 // Compute the size of the UTF-8 string. Start at the specified offset. |
6597 Access<StringInputBuffer> buffer( | 6598 Access<ConsStringIteratorOp> op( |
6598 heap->isolate()->objects_string_input_buffer()); | 6599 heap->isolate()->objects_string_iterator()); |
6599 buffer->Reset(offset, this); | 6600 StringCharacterStream stream(this, op.value(), offset); |
6600 int character_position = offset; | 6601 int character_position = offset; |
6601 int utf8_bytes = 0; | 6602 int utf8_bytes = 0; |
6602 int last = unibrow::Utf16::kNoPreviousCharacter; | 6603 int last = unibrow::Utf16::kNoPreviousCharacter; |
6603 while (buffer->has_more() && character_position++ < offset + length) { | 6604 while (stream.HasMore() && character_position++ < offset + length) { |
6604 uint16_t character = buffer->GetNext(); | 6605 uint16_t character = stream.GetNext(); |
6605 utf8_bytes += unibrow::Utf8::Length(character, last); | 6606 utf8_bytes += unibrow::Utf8::Length(character, last); |
6606 last = character; | 6607 last = character; |
6607 } | 6608 } |
6608 | 6609 |
6609 if (length_return) { | 6610 if (length_return) { |
6610 *length_return = utf8_bytes; | 6611 *length_return = utf8_bytes; |
6611 } | 6612 } |
6612 | 6613 |
6613 char* result = NewArray<char>(utf8_bytes + 1); | 6614 char* result = NewArray<char>(utf8_bytes + 1); |
6614 | 6615 |
6615 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. | 6616 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. |
6616 buffer->Rewind(); | 6617 stream.Reset(this, offset); |
6617 buffer->Seek(offset); | |
6618 character_position = offset; | 6618 character_position = offset; |
6619 int utf8_byte_position = 0; | 6619 int utf8_byte_position = 0; |
6620 last = unibrow::Utf16::kNoPreviousCharacter; | 6620 last = unibrow::Utf16::kNoPreviousCharacter; |
6621 while (buffer->has_more() && character_position++ < offset + length) { | 6621 while (stream.HasMore() && character_position++ < offset + length) { |
6622 uint16_t character = buffer->GetNext(); | 6622 uint16_t character = stream.GetNext(); |
6623 if (allow_nulls == DISALLOW_NULLS && character == 0) { | 6623 if (allow_nulls == DISALLOW_NULLS && character == 0) { |
6624 character = ' '; | 6624 character = ' '; |
6625 } | 6625 } |
6626 utf8_byte_position += | 6626 utf8_byte_position += |
6627 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); | 6627 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); |
6628 last = character; | 6628 last = character; |
6629 } | 6629 } |
6630 result[utf8_byte_position] = 0; | 6630 result[utf8_byte_position] = 0; |
6631 return SmartArrayPointer<char>(result); | 6631 return SmartArrayPointer<char>(result); |
6632 } | 6632 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6664 return NULL; | 6664 return NULL; |
6665 } | 6665 } |
6666 | 6666 |
6667 | 6667 |
6668 SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) { | 6668 SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) { |
6669 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { | 6669 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { |
6670 return SmartArrayPointer<uc16>(); | 6670 return SmartArrayPointer<uc16>(); |
6671 } | 6671 } |
6672 Heap* heap = GetHeap(); | 6672 Heap* heap = GetHeap(); |
6673 | 6673 |
6674 Access<StringInputBuffer> buffer( | 6674 Access<ConsStringIteratorOp> op( |
6675 heap->isolate()->objects_string_input_buffer()); | 6675 heap->isolate()->objects_string_iterator()); |
6676 buffer->Reset(this); | 6676 StringCharacterStream stream(this, op.value()); |
6677 | 6677 |
6678 uc16* result = NewArray<uc16>(length() + 1); | 6678 uc16* result = NewArray<uc16>(length() + 1); |
6679 | 6679 |
6680 int i = 0; | 6680 int i = 0; |
6681 while (buffer->has_more()) { | 6681 while (stream.HasMore()) { |
6682 uint16_t character = buffer->GetNext(); | 6682 uint16_t character = stream.GetNext(); |
6683 result[i++] = character; | 6683 result[i++] = character; |
6684 } | 6684 } |
6685 result[i] = 0; | 6685 result[i] = 0; |
6686 return SmartArrayPointer<uc16>(result); | 6686 return SmartArrayPointer<uc16>(result); |
6687 } | 6687 } |
6688 | 6688 |
6689 | 6689 |
6690 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { | 6690 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { |
6691 return reinterpret_cast<uc16*>( | 6691 return reinterpret_cast<uc16*>( |
6692 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; | 6692 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; |
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7450 SlicedString* slice = SlicedString::cast(source); | 7450 SlicedString* slice = SlicedString::cast(source); |
7451 unsigned offset = slice->offset(); | 7451 unsigned offset = slice->offset(); |
7452 WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 7452 WriteToFlat(slice->parent(), sink, from + offset, to + offset); |
7453 return; | 7453 return; |
7454 } | 7454 } |
7455 } | 7455 } |
7456 } | 7456 } |
7457 } | 7457 } |
7458 | 7458 |
7459 | 7459 |
7460 template <typename IteratorA, typename IteratorB> | |
7461 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { | |
7462 // General slow case check. We know that the ia and ib iterators | |
7463 // have the same length. | |
7464 while (ia->has_more()) { | |
7465 uint32_t ca = ia->GetNext(); | |
7466 uint32_t cb = ib->GetNext(); | |
7467 ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode); | |
7468 ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode); | |
7469 if (ca != cb) | |
7470 return false; | |
7471 } | |
7472 return true; | |
7473 } | |
7474 | |
7475 | |
7476 // Compares the contents of two strings by reading and comparing | 7460 // Compares the contents of two strings by reading and comparing |
7477 // int-sized blocks of characters. | 7461 // int-sized blocks of characters. |
7478 template <typename Char> | 7462 template <typename Char> |
7479 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { | 7463 static inline bool CompareRawStringContents(const Char* const a, |
7480 int length = a.length(); | 7464 const Char* const b, |
7481 ASSERT_EQ(length, b.length()); | 7465 int length) { |
7482 const Char* pa = a.start(); | |
7483 const Char* pb = b.start(); | |
7484 int i = 0; | 7466 int i = 0; |
7485 #ifndef V8_HOST_CAN_READ_UNALIGNED | 7467 #ifndef V8_HOST_CAN_READ_UNALIGNED |
7486 // If this architecture isn't comfortable reading unaligned ints | 7468 // If this architecture isn't comfortable reading unaligned ints |
7487 // then we have to check that the strings are aligned before | 7469 // then we have to check that the strings are aligned before |
7488 // comparing them blockwise. | 7470 // comparing them blockwise. |
7489 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT | 7471 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT |
7490 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa); | 7472 uint32_t pa_addr = reinterpret_cast<uint32_t>(a); |
7491 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb); | 7473 uint32_t pb_addr = reinterpret_cast<uint32_t>(b); |
7492 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) { | 7474 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) { |
7493 #endif | 7475 #endif |
7494 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT | 7476 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT |
7495 int endpoint = length - kStepSize; | 7477 int endpoint = length - kStepSize; |
7496 // Compare blocks until we reach near the end of the string. | 7478 // Compare blocks until we reach near the end of the string. |
7497 for (; i <= endpoint; i += kStepSize) { | 7479 for (; i <= endpoint; i += kStepSize) { |
7498 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i); | 7480 uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i); |
7499 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i); | 7481 uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i); |
7500 if (wa != wb) { | 7482 if (wa != wb) { |
7501 return false; | 7483 return false; |
7502 } | 7484 } |
7503 } | 7485 } |
7504 #ifndef V8_HOST_CAN_READ_UNALIGNED | 7486 #ifndef V8_HOST_CAN_READ_UNALIGNED |
7505 } | 7487 } |
7506 #endif | 7488 #endif |
7507 // Compare the remaining characters that didn't fit into a block. | 7489 // Compare the remaining characters that didn't fit into a block. |
7508 for (; i < length; i++) { | 7490 for (; i < length; i++) { |
7509 if (a[i] != b[i]) { | 7491 if (a[i] != b[i]) { |
7510 return false; | 7492 return false; |
7511 } | 7493 } |
7512 } | 7494 } |
7513 return true; | 7495 return true; |
7514 } | 7496 } |
7515 | 7497 |
7516 | 7498 |
7517 template <typename IteratorA> | 7499 template<typename Chars1, typename Chars2> |
7518 static inline bool CompareStringContentsPartial(Isolate* isolate, | 7500 class RawStringComparator : public AllStatic { |
7519 IteratorA* ia, | 7501 public: |
7520 String* b) { | 7502 static inline bool compare(const Chars1* a, const Chars2* b, int len) { |
7521 String::FlatContent content = b->GetFlatContent(); | 7503 ASSERT(sizeof(Chars1) != sizeof(Chars2)); |
7522 if (content.IsFlat()) { | 7504 for (int i = 0; i < len; i++) { |
7523 if (content.IsAscii()) { | 7505 if (a[i] != b[i]) { |
7524 VectorIterator<char> ib(content.ToAsciiVector()); | 7506 return false; |
7525 return CompareStringContents(ia, &ib); | 7507 } |
7526 } else { | |
7527 VectorIterator<uc16> ib(content.ToUC16Vector()); | |
7528 return CompareStringContents(ia, &ib); | |
7529 } | 7508 } |
7530 } else { | 7509 return true; |
7531 isolate->objects_string_compare_buffer_b()->Reset(0, b); | |
7532 return CompareStringContents(ia, | |
7533 isolate->objects_string_compare_buffer_b()); | |
7534 } | 7510 } |
7535 } | 7511 }; |
| 7512 |
| 7513 |
| 7514 template<> |
| 7515 class RawStringComparator<uint16_t, uint16_t> { |
| 7516 public: |
| 7517 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { |
| 7518 return CompareRawStringContents(a, b, len); |
| 7519 } |
| 7520 }; |
| 7521 |
| 7522 |
| 7523 template<> |
| 7524 class RawStringComparator<uint8_t, uint8_t> { |
| 7525 public: |
| 7526 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { |
| 7527 return CompareRawStringContents(a, b, len); |
| 7528 } |
| 7529 }; |
| 7530 |
| 7531 |
| 7532 class StringComparator { |
| 7533 class State { |
| 7534 public: |
| 7535 explicit inline State(ConsStringIteratorOp* op) |
| 7536 : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {} |
| 7537 |
| 7538 inline void Init(String* string, unsigned len) { |
| 7539 op_->Reset(); |
| 7540 int32_t type = string->map()->instance_type(); |
| 7541 String::Visit(string, 0, *this, *op_, type, len); |
| 7542 } |
| 7543 |
| 7544 inline void VisitOneByteString(const uint8_t* chars, unsigned length) { |
| 7545 is_one_byte_ = true; |
| 7546 buffer8_ = chars; |
| 7547 length_ = length; |
| 7548 } |
| 7549 |
| 7550 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) { |
| 7551 is_one_byte_ = false; |
| 7552 buffer16_ = chars; |
| 7553 length_ = length; |
| 7554 } |
| 7555 |
| 7556 void Advance(unsigned consumed) { |
| 7557 ASSERT(consumed <= length_); |
| 7558 // Still in buffer. |
| 7559 if (length_ != consumed) { |
| 7560 if (is_one_byte_) { |
| 7561 buffer8_ += consumed; |
| 7562 } else { |
| 7563 buffer16_ += consumed; |
| 7564 } |
| 7565 length_ -= consumed; |
| 7566 return; |
| 7567 } |
| 7568 // Advance state. |
| 7569 ASSERT(op_->HasMore()); |
| 7570 int32_t type = 0; |
| 7571 unsigned length = 0; |
| 7572 String* next = op_->ContinueOperation(&type, &length); |
| 7573 ASSERT(next != NULL); |
| 7574 ConsStringNullOp null_op; |
| 7575 String::Visit(next, 0, *this, null_op, type, length); |
| 7576 } |
| 7577 |
| 7578 ConsStringIteratorOp* const op_; |
| 7579 bool is_one_byte_; |
| 7580 unsigned length_; |
| 7581 union { |
| 7582 const uint8_t* buffer8_; |
| 7583 const uint16_t* buffer16_; |
| 7584 }; |
| 7585 DISALLOW_IMPLICIT_CONSTRUCTORS(State); |
| 7586 }; |
| 7587 |
| 7588 public: |
| 7589 inline StringComparator(ConsStringIteratorOp* op_1, |
| 7590 ConsStringIteratorOp* op_2) |
| 7591 : state_1_(op_1), |
| 7592 state_2_(op_2) { |
| 7593 } |
| 7594 |
| 7595 template<typename Chars1, typename Chars2> |
| 7596 static inline bool Equals(State* state_1, State* state_2, unsigned to_check) { |
| 7597 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); |
| 7598 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); |
| 7599 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); |
| 7600 } |
| 7601 |
| 7602 bool Equals(unsigned length, String* string_1, String* string_2) { |
| 7603 ASSERT(length != 0); |
| 7604 state_1_.Init(string_1, length); |
| 7605 state_2_.Init(string_2, length); |
| 7606 while (true) { |
| 7607 unsigned to_check = Min(state_1_.length_, state_2_.length_); |
| 7608 ASSERT(to_check > 0 && to_check <= length); |
| 7609 bool is_equal; |
| 7610 if (state_1_.is_one_byte_) { |
| 7611 if (state_2_.is_one_byte_) { |
| 7612 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); |
| 7613 } else { |
| 7614 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); |
| 7615 } |
| 7616 } else { |
| 7617 if (state_2_.is_one_byte_) { |
| 7618 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); |
| 7619 } else { |
| 7620 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); |
| 7621 } |
| 7622 } |
| 7623 // Looping done. |
| 7624 if (!is_equal) return false; |
| 7625 length -= to_check; |
| 7626 // Exit condition. Strings are equal. |
| 7627 if (length == 0) return true; |
| 7628 state_1_.Advance(to_check); |
| 7629 state_2_.Advance(to_check); |
| 7630 } |
| 7631 } |
| 7632 |
| 7633 private: |
| 7634 State state_1_; |
| 7635 State state_2_; |
| 7636 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator); |
| 7637 }; |
7536 | 7638 |
7537 | 7639 |
7538 bool String::SlowEquals(String* other) { | 7640 bool String::SlowEquals(String* other) { |
7539 // Fast check: negative check with lengths. | 7641 // Fast check: negative check with lengths. |
7540 int len = length(); | 7642 int len = length(); |
7541 if (len != other->length()) return false; | 7643 if (len != other->length()) return false; |
7542 if (len == 0) return true; | 7644 if (len == 0) return true; |
7543 | 7645 |
7544 // Fast check: if hash code is computed for both strings | 7646 // Fast check: if hash code is computed for both strings |
7545 // a fast negative check can be performed. | 7647 // a fast negative check can be performed. |
(...skipping 15 matching lines...) Expand all Loading... |
7561 if (Hash() != other->Hash()) return false; | 7663 if (Hash() != other->Hash()) return false; |
7562 } | 7664 } |
7563 | 7665 |
7564 // We know the strings are both non-empty. Compare the first chars | 7666 // We know the strings are both non-empty. Compare the first chars |
7565 // before we try to flatten the strings. | 7667 // before we try to flatten the strings. |
7566 if (this->Get(0) != other->Get(0)) return false; | 7668 if (this->Get(0) != other->Get(0)) return false; |
7567 | 7669 |
7568 String* lhs = this->TryFlattenGetString(); | 7670 String* lhs = this->TryFlattenGetString(); |
7569 String* rhs = other->TryFlattenGetString(); | 7671 String* rhs = other->TryFlattenGetString(); |
7570 | 7672 |
| 7673 // TODO(dcarney): Compare all types of flat strings with a Visitor. |
7571 if (StringShape(lhs).IsSequentialAscii() && | 7674 if (StringShape(lhs).IsSequentialAscii() && |
7572 StringShape(rhs).IsSequentialAscii()) { | 7675 StringShape(rhs).IsSequentialAscii()) { |
7573 const char* str1 = SeqOneByteString::cast(lhs)->GetChars(); | 7676 const char* str1 = SeqOneByteString::cast(lhs)->GetChars(); |
7574 const char* str2 = SeqOneByteString::cast(rhs)->GetChars(); | 7677 const char* str2 = SeqOneByteString::cast(rhs)->GetChars(); |
7575 return CompareRawStringContents(Vector<const char>(str1, len), | 7678 return CompareRawStringContents(str1, str2, len); |
7576 Vector<const char>(str2, len)); | |
7577 } | 7679 } |
7578 | 7680 |
7579 Isolate* isolate = GetIsolate(); | 7681 Isolate* isolate = GetIsolate(); |
7580 String::FlatContent lhs_content = lhs->GetFlatContent(); | 7682 StringComparator comparator(isolate->objects_string_compare_iterator_a(), |
7581 String::FlatContent rhs_content = rhs->GetFlatContent(); | 7683 isolate->objects_string_compare_iterator_b()); |
7582 if (lhs_content.IsFlat()) { | 7684 |
7583 if (lhs_content.IsAscii()) { | 7685 return comparator.Equals(static_cast<unsigned>(len), lhs, rhs); |
7584 Vector<const char> vec1 = lhs_content.ToAsciiVector(); | |
7585 if (rhs_content.IsFlat()) { | |
7586 if (rhs_content.IsAscii()) { | |
7587 Vector<const char> vec2 = rhs_content.ToAsciiVector(); | |
7588 return CompareRawStringContents(vec1, vec2); | |
7589 } else { | |
7590 VectorIterator<char> buf1(vec1); | |
7591 VectorIterator<uc16> ib(rhs_content.ToUC16Vector()); | |
7592 return CompareStringContents(&buf1, &ib); | |
7593 } | |
7594 } else { | |
7595 VectorIterator<char> buf1(vec1); | |
7596 isolate->objects_string_compare_buffer_b()->Reset(0, rhs); | |
7597 return CompareStringContents(&buf1, | |
7598 isolate->objects_string_compare_buffer_b()); | |
7599 } | |
7600 } else { | |
7601 Vector<const uc16> vec1 = lhs_content.ToUC16Vector(); | |
7602 if (rhs_content.IsFlat()) { | |
7603 if (rhs_content.IsAscii()) { | |
7604 VectorIterator<uc16> buf1(vec1); | |
7605 VectorIterator<char> ib(rhs_content.ToAsciiVector()); | |
7606 return CompareStringContents(&buf1, &ib); | |
7607 } else { | |
7608 Vector<const uc16> vec2(rhs_content.ToUC16Vector()); | |
7609 return CompareRawStringContents(vec1, vec2); | |
7610 } | |
7611 } else { | |
7612 VectorIterator<uc16> buf1(vec1); | |
7613 isolate->objects_string_compare_buffer_b()->Reset(0, rhs); | |
7614 return CompareStringContents(&buf1, | |
7615 isolate->objects_string_compare_buffer_b()); | |
7616 } | |
7617 } | |
7618 } else { | |
7619 isolate->objects_string_compare_buffer_a()->Reset(0, lhs); | |
7620 return CompareStringContentsPartial(isolate, | |
7621 isolate->objects_string_compare_buffer_a(), rhs); | |
7622 } | |
7623 } | 7686 } |
7624 | 7687 |
7625 | 7688 |
7626 bool String::MarkAsUndetectable() { | 7689 bool String::MarkAsUndetectable() { |
7627 if (StringShape(this).IsSymbol()) return false; | 7690 if (StringShape(this).IsSymbol()) return false; |
7628 | 7691 |
7629 Map* map = this->map(); | 7692 Map* map = this->map(); |
7630 Heap* heap = GetHeap(); | 7693 Heap* heap = GetHeap(); |
7631 if (map == heap->string_map()) { | 7694 if (map == heap->string_map()) { |
7632 this->set_map(heap->undetectable_string_map()); | 7695 this->set_map(heap->undetectable_string_map()); |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7757 set_hash_field(field); | 7820 set_hash_field(field); |
7758 | 7821 |
7759 // Check the hash code is there. | 7822 // Check the hash code is there. |
7760 ASSERT(HasHashCode()); | 7823 ASSERT(HasHashCode()); |
7761 uint32_t result = field >> kHashShift; | 7824 uint32_t result = field >> kHashShift; |
7762 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. | 7825 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. |
7763 return result; | 7826 return result; |
7764 } | 7827 } |
7765 | 7828 |
7766 | 7829 |
7767 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer, | 7830 bool String::ComputeArrayIndex(uint32_t* index) { |
7768 uint32_t* index, | 7831 int length = this->length(); |
7769 int length) { | |
7770 if (length == 0 || length > kMaxArrayIndexSize) return false; | 7832 if (length == 0 || length > kMaxArrayIndexSize) return false; |
7771 uc32 ch = buffer->GetNext(); | 7833 ConsStringIteratorOp op; |
| 7834 StringCharacterStream stream(this, &op); |
| 7835 uint16_t ch = stream.GetNext(); |
7772 | 7836 |
7773 // If the string begins with a '0' character, it must only consist | 7837 // If the string begins with a '0' character, it must only consist |
7774 // of it to be a legal array index. | 7838 // of it to be a legal array index. |
7775 if (ch == '0') { | 7839 if (ch == '0') { |
7776 *index = 0; | 7840 *index = 0; |
7777 return length == 1; | 7841 return length == 1; |
7778 } | 7842 } |
7779 | 7843 |
7780 // Convert string to uint32 array index; character by character. | 7844 // Convert string to uint32 array index; character by character. |
7781 int d = ch - '0'; | 7845 int d = ch - '0'; |
7782 if (d < 0 || d > 9) return false; | 7846 if (d < 0 || d > 9) return false; |
7783 uint32_t result = d; | 7847 uint32_t result = d; |
7784 while (buffer->has_more()) { | 7848 while (stream.HasMore()) { |
7785 d = buffer->GetNext() - '0'; | 7849 d = stream.GetNext() - '0'; |
7786 if (d < 0 || d > 9) return false; | 7850 if (d < 0 || d > 9) return false; |
7787 // Check that the new result is below the 32 bit limit. | 7851 // Check that the new result is below the 32 bit limit. |
7788 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; | 7852 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; |
7789 result = (result * 10) + d; | 7853 result = (result * 10) + d; |
7790 } | 7854 } |
7791 | 7855 |
7792 *index = result; | 7856 *index = result; |
7793 return true; | 7857 return true; |
7794 } | 7858 } |
7795 | 7859 |
7796 | 7860 |
7797 bool String::SlowAsArrayIndex(uint32_t* index) { | 7861 bool String::SlowAsArrayIndex(uint32_t* index) { |
7798 if (length() <= kMaxCachedArrayIndexLength) { | 7862 if (length() <= kMaxCachedArrayIndexLength) { |
7799 Hash(); // force computation of hash code | 7863 Hash(); // force computation of hash code |
7800 uint32_t field = hash_field(); | 7864 uint32_t field = hash_field(); |
7801 if ((field & kIsNotArrayIndexMask) != 0) return false; | 7865 if ((field & kIsNotArrayIndexMask) != 0) return false; |
7802 // Isolate the array index form the full hash field. | 7866 // Isolate the array index form the full hash field. |
7803 *index = (kArrayIndexHashMask & field) >> kHashShift; | 7867 *index = (kArrayIndexHashMask & field) >> kHashShift; |
7804 return true; | 7868 return true; |
7805 } else { | 7869 } else { |
7806 StringInputBuffer buffer(this); | 7870 return ComputeArrayIndex(index); |
7807 return ComputeArrayIndex(&buffer, index, length()); | |
7808 } | 7871 } |
7809 } | 7872 } |
7810 | 7873 |
7811 | 7874 |
7812 String* SeqString::Truncate(int new_length) { | 7875 String* SeqString::Truncate(int new_length) { |
7813 Heap* heap = GetHeap(); | 7876 Heap* heap = GetHeap(); |
7814 if (new_length <= 0) return heap->empty_string(); | 7877 if (new_length <= 0) return heap->empty_string(); |
7815 | 7878 |
7816 int string_size, allocated_string_size; | 7879 int string_size, allocated_string_size; |
7817 int old_length = length(); | 7880 int old_length = length(); |
(...skipping 6261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14079 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 14142 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
14080 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 14143 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
14081 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 14144 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
14082 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 14145 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
14083 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 14146 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
14084 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 14147 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
14085 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 14148 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
14086 } | 14149 } |
14087 | 14150 |
14088 } } // namespace v8::internal | 14151 } } // namespace v8::internal |
OLD | NEW |