Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 } | 514 } |
| 515 case kConsStringTag: { | 515 case kConsStringTag: { |
| 516 ConsString* cs = ConsString::cast(this); | 516 ConsString* cs = ConsString::cast(this); |
| 517 if (String::cast(cs->second())->length() == 0) { | 517 if (String::cast(cs->second())->length() == 0) { |
| 518 return this; | 518 return this; |
| 519 } | 519 } |
| 520 // There's little point in putting the flat string in new space if the | 520 // There's little point in putting the flat string in new space if the |
| 521 // cons string is in old space. It can never get GCed until there is | 521 // cons string is in old space. It can never get GCed until there is |
| 522 // an old space GC. | 522 // an old space GC. |
| 523 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; | 523 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; |
| 524 int len = length(); | |
| 524 Object* object = IsAscii() ? | 525 Object* object = IsAscii() ? |
| 525 Heap::AllocateRawAsciiString(length(), tenure) : | 526 Heap::AllocateRawAsciiString(len, tenure) : |
| 526 Heap::AllocateRawTwoByteString(length(), tenure); | 527 Heap::AllocateRawTwoByteString(len, tenure); |
| 527 if (object->IsFailure()) return object; | 528 if (object->IsFailure()) return object; |
| 528 String* result = String::cast(object); | 529 String* result = String::cast(object); |
| 529 Flatten(this, result, 0, length(), 0); | 530 StringHasher hasher(len); |
| 531 Flatten(this, result, 0, len, 0, &hasher); | |
| 532 if (hasher.is_valid()) { | |
| 533 #ifdef DEBUG | |
| 534 result->ComputeAndSetHash(); | |
| 535 ASSERT(result->length_field() == hasher.GetHashField()); | |
| 536 #else | |
| 537 result->set_length_field(hasher.GetHashField()); | |
| 538 #endif | |
| 539 Heap::LookupSymbolIfExists(result, &result); | |
| 540 } | |
| 530 cs->set_first(result); | 541 cs->set_first(result); |
| 531 cs->set_second(Heap::empty_string()); | 542 cs->set_second(Heap::empty_string()); |
| 532 return this; | 543 return this; |
| 533 } | 544 } |
| 534 default: | 545 default: |
| 535 return this; | 546 return this; |
| 536 } | 547 } |
| 537 } | 548 } |
| 538 | 549 |
| 539 | 550 |
| (...skipping 3059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3599 String* buf = String::cast(buffer()); | 3610 String* buf = String::cast(buffer()); |
| 3600 ASSERT(!buf->StringIsSlicedString()); | 3611 ASSERT(!buf->StringIsSlicedString()); |
| 3601 if (buf->StringIsConsString()) { | 3612 if (buf->StringIsConsString()) { |
| 3602 Object* ok = buf->Flatten(); | 3613 Object* ok = buf->Flatten(); |
| 3603 if (ok->IsFailure()) return ok; | 3614 if (ok->IsFailure()) return ok; |
| 3604 } | 3615 } |
| 3605 return this; | 3616 return this; |
| 3606 } | 3617 } |
| 3607 | 3618 |
| 3608 | 3619 |
| 3609 void String::Flatten(String* src, String* sink, int f, int t, int so) { | 3620 void String::Flatten(String* src, |
| 3621 String* sink, | |
| 3622 int f, | |
| 3623 int t, | |
| 3624 int so, | |
| 3625 StringHasher* hasher) { | |
| 3610 String* source = src; | 3626 String* source = src; |
| 3611 int from = f; | 3627 int from = f; |
| 3612 int to = t; | 3628 int to = t; |
| 3613 int sink_offset = so; | 3629 int sink_offset = so; |
| 3614 while (true) { | 3630 while (true) { |
| 3615 ASSERT(0 <= from && from <= to && to <= source->length()); | 3631 ASSERT(0 <= from && from <= to && to <= source->length()); |
| 3616 ASSERT(0 <= sink_offset && sink_offset < sink->length()); | 3632 ASSERT(0 <= sink_offset && sink_offset < sink->length()); |
| 3617 switch (source->representation_tag()) { | 3633 switch (source->representation_tag()) { |
| 3618 case kSeqStringTag: | 3634 case kSeqStringTag: |
| 3619 case kExternalStringTag: { | 3635 case kExternalStringTag: { |
| 3620 Access<StringInputBuffer> buffer(&string_input_buffer); | 3636 Access<StringInputBuffer> buffer(&string_input_buffer); |
| 3621 buffer->Reset(from, source); | 3637 buffer->Reset(from, source); |
| 3622 int j = sink_offset; | 3638 int j = sink_offset; |
| 3623 for (int i = from; i < to; i++) { | 3639 for (int i = from; i < to; i++) { |
| 3624 sink->Set(j++, buffer->GetNext()); | 3640 uc32 c = buffer->GetNext(); |
| 3641 if (hasher->is_valid()) | |
| 3642 hasher->AddCharacter(c); | |
| 3643 sink->Set(j++, c); | |
| 3625 } | 3644 } |
| 3626 return; | 3645 return; |
| 3627 } | 3646 } |
| 3628 case kSlicedStringTag: { | 3647 case kSlicedStringTag: { |
| 3629 SlicedString* sliced_string = SlicedString::cast(source); | 3648 SlicedString* sliced_string = SlicedString::cast(source); |
| 3630 int start = sliced_string->start(); | 3649 int start = sliced_string->start(); |
| 3631 from += start; | 3650 from += start; |
| 3632 to += start; | 3651 to += start; |
| 3633 source = String::cast(sliced_string->buffer()); | 3652 source = String::cast(sliced_string->buffer()); |
| 3634 } | 3653 } |
| 3635 break; | 3654 break; |
| 3636 case kConsStringTag: { | 3655 case kConsStringTag: { |
| 3637 ConsString* cons_string = ConsString::cast(source); | 3656 ConsString* cons_string = ConsString::cast(source); |
| 3638 String* first = String::cast(cons_string->first()); | 3657 String* first = String::cast(cons_string->first()); |
| 3639 int boundary = first->length(); | 3658 int boundary = first->length(); |
| 3640 if (to - boundary > boundary - from) { | 3659 if (to - boundary > boundary - from) { |
|
Erik Corry
2008/10/07 10:04:34
>=
| |
| 3641 // Right hand side is longer. Recurse over left. | 3660 // Right hand side is longer. Recurse over left. |
| 3642 if (from < boundary) { | 3661 if (from < boundary) { |
| 3643 Flatten(first, sink, from, boundary, sink_offset); | 3662 Flatten(first, sink, from, boundary, sink_offset, hasher); |
| 3644 sink_offset += boundary - from; | 3663 sink_offset += boundary - from; |
| 3645 from = 0; | 3664 from = 0; |
| 3646 } else { | 3665 } else { |
| 3647 from -= boundary; | 3666 from -= boundary; |
| 3648 } | 3667 } |
| 3649 to -= boundary; | 3668 to -= boundary; |
| 3650 source = String::cast(cons_string->second()); | 3669 source = String::cast(cons_string->second()); |
| 3651 } else { | 3670 } else { |
| 3652 // Left hand side is longer. Recurse over right. | 3671 // Left hand side is longer. Recurse over right. The hasher |
| 3672 // needs us to visit the string from left to right so doing | |
| 3673 // this invalidates that hash. | |
| 3674 hasher->invalidate(); | |
| 3653 if (to > boundary) { | 3675 if (to > boundary) { |
| 3654 String* second = String::cast(cons_string->second()); | 3676 String* second = String::cast(cons_string->second()); |
| 3655 Flatten(second, | 3677 Flatten(second, |
| 3656 sink, | 3678 sink, |
| 3657 0, | 3679 0, |
| 3658 to - boundary, | 3680 to - boundary, |
| 3659 sink_offset + boundary - from); | 3681 sink_offset + boundary - from, |
| 3682 hasher); | |
| 3660 to = boundary; | 3683 to = boundary; |
| 3661 } | 3684 } |
| 3662 source = first; | 3685 source = first; |
| 3663 } | 3686 } |
| 3664 } | 3687 } |
| 3665 break; | 3688 break; |
| 3666 } | 3689 } |
| 3667 } | 3690 } |
| 3668 } | 3691 } |
| 3669 | 3692 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3805 StringInputBuffer buffer(this); | 3828 StringInputBuffer buffer(this); |
| 3806 return ComputeArrayIndex(&buffer, index, length()); | 3829 return ComputeArrayIndex(&buffer, index, length()); |
| 3807 } | 3830 } |
| 3808 | 3831 |
| 3809 | 3832 |
| 3810 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { | 3833 static inline uint32_t HashField(uint32_t hash, bool is_array_index) { |
| 3811 return (hash << String::kLongLengthShift) | (is_array_index ? 3 : 1); | 3834 return (hash << String::kLongLengthShift) | (is_array_index ? 3 : 1); |
| 3812 } | 3835 } |
| 3813 | 3836 |
| 3814 | 3837 |
| 3838 uint32_t StringHasher::GetHashField() { | |
| 3839 ASSERT(is_valid()); | |
| 3840 if (length_ <= String::kMaxShortStringSize) { | |
| 3841 uint32_t payload; | |
| 3842 if (is_array_index()) { | |
| 3843 payload = v8::internal::HashField(array_index(), true); | |
| 3844 } else { | |
| 3845 payload = v8::internal::HashField(GetHash(), false); | |
| 3846 } | |
| 3847 return (payload & 0x00FFFFFF) | (length_ << String::kShortLengthShift); | |
| 3848 } else if (length_ <= String::kMaxMediumStringSize) { | |
| 3849 uint32_t payload = v8::internal::HashField(GetHash(), false); | |
| 3850 return (payload & 0x0000FFFF) | (length_ << String::kMediumLengthShift); | |
| 3851 } else { | |
| 3852 return v8::internal::HashField(length_, false); | |
| 3853 } | |
| 3854 } | |
| 3855 | |
| 3856 | |
| 3815 uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer, | 3857 uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer, |
| 3816 int length) { | 3858 int length) { |
| 3817 // Large string (please note large strings cannot be an array index). | 3859 StringHasher hasher(length); |
| 3818 if (length > kMaxMediumStringSize) return HashField(length, false); | |
| 3819 | 3860 |
| 3820 // Note: the Jenkins one-at-a-time hash function | 3861 // Very long strings have a trivial hash that doesn't inspect the |
| 3821 uint32_t hash = 0; | 3862 // string contents. |
| 3822 while (buffer->has_more()) { | 3863 if (hasher.has_trivial_hash()) |
| 3823 uc32 r = buffer->GetNext(); | 3864 return hasher.GetHashField(); |
| 3824 hash += r; | |
| 3825 hash += (hash << 10); | |
| 3826 hash ^= (hash >> 6); | |
| 3827 } | |
| 3828 hash += (hash << 3); | |
| 3829 hash ^= (hash >> 11); | |
| 3830 hash += (hash << 15); | |
| 3831 | 3865 |
| 3832 // Short string. | 3866 // Do the iterative array index computation as long as there is a |
| 3833 if (length <= kMaxShortStringSize) { | 3867 // chance this is an array index. |
| 3834 // Make hash value consistent with value returned from String::Hash. | 3868 while (buffer->has_more() && hasher.is_array_index()) |
| 3835 buffer->Rewind(); | 3869 hasher.AddCharacter(buffer->GetNext()); |
| 3836 uint32_t index; | |
| 3837 hash = HashField(hash, ComputeArrayIndex(buffer, &index, length)); | |
| 3838 hash = (hash & 0x00FFFFFF) | (length << kShortLengthShift); | |
| 3839 return hash; | |
| 3840 } | |
| 3841 | 3870 |
| 3842 // Medium string (please note medium strings cannot be an array index). | 3871 // Process the remaining characters without updating the array |
| 3843 ASSERT(length <= kMaxMediumStringSize); | 3872 // index. |
| 3844 // Make hash value consistent with value returned from String::Hash. | 3873 while (buffer->has_more()) |
| 3845 hash = HashField(hash, false); | 3874 hasher.AddCharacterNoIndex(buffer->GetNext()); |
| 3846 hash = (hash & 0x0000FFFF) | (length << kMediumLengthShift); | 3875 |
| 3847 return hash; | 3876 return hasher.GetHashField(); |
| 3848 } | 3877 } |
| 3849 | 3878 |
| 3850 | 3879 |
| 3851 Object* String::Slice(int start, int end) { | 3880 Object* String::Slice(int start, int end) { |
| 3852 if (start == 0 && end == length()) return this; | 3881 if (start == 0 && end == length()) return this; |
| 3853 int representation = representation_tag(); | 3882 int representation = representation_tag(); |
| 3854 if (representation == kSlicedStringTag) { | 3883 if (representation == kSlicedStringTag) { |
| 3855 // Translate slices of a SlicedString into slices of the | 3884 // Translate slices of a SlicedString into slices of the |
| 3856 // underlying string buffer. | 3885 // underlying string buffer. |
| 3857 SlicedString* str = SlicedString::cast(this); | 3886 SlicedString* str = SlicedString::cast(this); |
| (...skipping 1765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5623 // Force instantiation of EvalCache's base class | 5652 // Force instantiation of EvalCache's base class |
| 5624 template class HashTable<0, 2>; | 5653 template class HashTable<0, 2>; |
| 5625 | 5654 |
| 5626 | 5655 |
| 5627 Object* SymbolTable::LookupString(String* string, Object** s) { | 5656 Object* SymbolTable::LookupString(String* string, Object** s) { |
| 5628 SymbolKey key(string); | 5657 SymbolKey key(string); |
| 5629 return LookupKey(&key, s); | 5658 return LookupKey(&key, s); |
| 5630 } | 5659 } |
| 5631 | 5660 |
| 5632 | 5661 |
| 5662 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { | |
| 5663 SymbolKey key(string); | |
| 5664 int entry = FindEntry(&key); | |
| 5665 if (entry == -1) { | |
| 5666 return false; | |
| 5667 } else { | |
| 5668 String* result = String::cast(KeyAt(entry)); | |
| 5669 ASSERT(result->is_symbol()); | |
| 5670 *symbol = result; | |
| 5671 return true; | |
| 5672 } | |
| 5673 } | |
| 5674 | |
| 5675 | |
| 5633 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { | 5676 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { |
| 5634 Utf8SymbolKey key(str); | 5677 Utf8SymbolKey key(str); |
| 5635 return LookupKey(&key, s); | 5678 return LookupKey(&key, s); |
| 5636 } | 5679 } |
| 5637 | 5680 |
| 5638 | 5681 |
| 5639 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { | 5682 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { |
| 5640 int entry = FindEntry(key); | 5683 int entry = FindEntry(key); |
| 5641 | 5684 |
| 5642 // Symbol already in table. | 5685 // Symbol already in table. |
| (...skipping 773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6416 // No break point. | 6459 // No break point. |
| 6417 if (break_point_objects()->IsUndefined()) return 0; | 6460 if (break_point_objects()->IsUndefined()) return 0; |
| 6418 // Single beak point. | 6461 // Single beak point. |
| 6419 if (!break_point_objects()->IsFixedArray()) return 1; | 6462 if (!break_point_objects()->IsFixedArray()) return 1; |
| 6420 // Multiple break points. | 6463 // Multiple break points. |
| 6421 return FixedArray::cast(break_point_objects())->length(); | 6464 return FixedArray::cast(break_point_objects())->length(); |
| 6422 } | 6465 } |
| 6423 | 6466 |
| 6424 | 6467 |
| 6425 } } // namespace v8::internal | 6468 } } // namespace v8::internal |
| OLD | NEW |