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