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