Chromium Code Reviews| Index: src/objects.cc |
| =================================================================== |
| --- src/objects.cc (revision 654) |
| +++ src/objects.cc (working copy) |
| @@ -475,25 +475,26 @@ |
| // We don't use the BBC's overcorrect "an historic occasion" though if |
| // you speak a dialect you may well say "an 'istoric occasion". |
| static bool AnWord(String* str) { |
| - if (str->length() == 0) return false; // a nothing |
| - int c0 = str->Get(0); |
| - int c1 = str->length() > 1 ? str->Get(1) : 0; |
| + StringShape shape(str); |
| + if (str->length(shape) == 0) return false; // A nothing. |
| + int c0 = str->Get(shape, 0); |
| + int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0; |
| if (c0 == 'U') { |
| if (c1 > 'Z') { |
| - return true; // an Umpire, but a UTF8String, a U |
| + return true; // An Umpire, but a UTF8String, a U. |
| } |
| } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') { |
| - return true; // an Ape, an ABCBook |
| + return true; // An Ape, an ABCBook. |
| } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) && |
| (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' || |
| c0 == 'S' || c0 == 'X')) { |
| - return true; // an MP3File, an M |
| + return true; // An MP3File, an M. |
| } |
| return false; |
| } |
| -Object* String::Flatten() { |
| +Object* String::Flatten(StringShape shape) { |
| #ifdef DEBUG |
| // Do not attempt to flatten in debug mode when allocation is not |
| // allowed. This is to avoid an assertion failure when allocating. |
| @@ -502,44 +503,48 @@ |
| if (!Heap::IsAllocationAllowed()) return this; |
| #endif |
| - switch (representation_tag()) { |
| + switch (shape.representation_tag()) { |
| case kSlicedStringTag: { |
| SlicedString* ss = SlicedString::cast(this); |
| // The SlicedString constructor should ensure that there are no |
| // SlicedStrings that are constructed directly on top of other |
| // SlicedStrings. |
| - ASSERT(!ss->buffer()->IsSlicedString()); |
| - Object* ok = String::cast(ss->buffer())->Flatten(); |
| + String* buf = ss->buffer(); |
| + ASSERT(!buf->IsSlicedString()); |
| + Object* ok = buf->Flatten(StringShape(buf)); |
| if (ok->IsFailure()) return ok; |
| // Under certain circumstances (TryFlatten fails in String::Slice) |
| // we can have a cons string under a slice. In this case we need |
| // to get the flat string out of the cons! |
| - if (String::cast(ok)->StringIsConsString()) { |
| + if (StringShape(String::cast(ok)).IsCons()) { |
| ss->set_buffer(ConsString::cast(ok)->first()); |
| } |
| return this; |
| } |
| case kConsStringTag: { |
| ConsString* cs = ConsString::cast(this); |
| - if (String::cast(cs->second())->length() == 0) { |
| + if (cs->second()->length() == 0) { |
| return this; |
| } |
| // There's little point in putting the flat string in new space if the |
| // cons string is in old space. It can never get GCed until there is |
| // an old space GC. |
| PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED; |
| - int len = length(); |
| + int len = length(shape); |
| Object* object; |
| String* result; |
| - if (IsAsciiRepresentation()) { |
| + if (shape.IsAsciiRepresentation()) { |
| object = Heap::AllocateRawAsciiString(len, tenure); |
| if (object->IsFailure()) return object; |
| result = String::cast(object); |
| - String* first = String::cast(cs->first()); |
| - int first_length = first->length(); |
| + String* first = cs->first(); |
| + StringShape first_shape(first); |
| + int first_length = first->length(first_shape); |
| char* dest = SeqAsciiString::cast(result)->GetChars(); |
| - WriteToFlat(first, dest, 0, first_length); |
| - WriteToFlat(String::cast(cs->second()), |
| + WriteToFlat(first, first_shape, dest, 0, first_length); |
| + String* second = cs->second(); |
| + WriteToFlat(second, |
| + StringShape(second), |
| dest + first_length, |
| 0, |
| len - first_length); |
| @@ -548,10 +553,13 @@ |
| if (object->IsFailure()) return object; |
| result = String::cast(object); |
| uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
| - String* first = String::cast(cs->first()); |
| - int first_length = first->length(); |
| - WriteToFlat(first, dest, 0, first_length); |
| - WriteToFlat(String::cast(cs->second()), |
| + String* first = cs->first(); |
| + StringShape first_shape(first); |
| + int first_length = first->length(first_shape); |
| + WriteToFlat(first, first_shape, dest, 0, first_length); |
| + String* second = cs->second(); |
| + WriteToFlat(second, |
| + StringShape(second), |
| dest + first_length, |
| 0, |
| len - first_length); |
| @@ -567,7 +575,8 @@ |
| void String::StringShortPrint(StringStream* accumulator) { |
| - int len = length(); |
| + StringShape shape(this); |
| + int len = length(shape); |
| if (len > kMaxMediumStringSize) { |
| accumulator->Add("<Very long string[%u]>", len); |
| return; |
| @@ -595,7 +604,7 @@ |
| } |
| buf.Reset(this); |
| if (ascii) { |
| - accumulator->Add("<String[%u]: ", length()); |
| + accumulator->Add("<String[%u]: ", length(shape)); |
| for (int i = 0; i < len; i++) { |
| accumulator->Put(buf.GetNext()); |
| } |
| @@ -603,7 +612,7 @@ |
| } else { |
| // Backslash indicates that the string contains control |
| // characters and that backslashes are therefore escaped. |
| - accumulator->Add("<String[%u]\\: ", length()); |
| + accumulator->Add("<String[%u]\\: ", length(shape)); |
| for (int i = 0; i < len; i++) { |
| int c = buf.GetNext(); |
| if (c == '\n') { |
| @@ -781,13 +790,13 @@ |
| InstanceType instance_type = map->instance_type(); |
| if (instance_type < FIRST_NONSTRING_TYPE |
| - && (reinterpret_cast<String*>(this)->map_representation_tag(map) |
| - == kSeqStringTag)) { |
| - if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) { |
| - return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map); |
| + && (StringShape(instance_type).IsSequential())) { |
| + StringShape shape(instance_type); |
| + if (shape.IsAsciiRepresentation()) { |
| + return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape); |
| } else { |
| SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this); |
| - return self->SeqTwoByteStringSize(map); |
| + return self->SeqTwoByteStringSize(shape); |
| } |
| } |
| @@ -2279,7 +2288,7 @@ |
| } |
| // TryFlatten before operating on the string. |
| - name->TryFlatten(); |
| + name->TryFlatten(StringShape(name)); |
| // Make sure name is not an index. |
| uint32_t index; |
| @@ -2902,27 +2911,21 @@ |
| bool String::LooksValid() { |
| - if (!Heap::Contains(this)) |
| - return false; |
| - switch (representation_tag()) { |
| - case kSeqStringTag: |
| - case kConsStringTag: |
| - case kSlicedStringTag: |
| - case kExternalStringTag: |
| - return true; |
| - default: |
| - return false; |
| - } |
| + if (!Heap::Contains(this)) return false; |
| + return true; |
|
Mads Ager (chromium)
2008/11/03 08:45:49
Doesn't it make sense to check that the representa
Erik Corry
2008/11/03 09:33:54
It makes no sense because all bit combinations are
|
| } |
| int String::Utf8Length() { |
| - if (is_ascii_representation()) return length(); |
| + StringShape shape(this); |
| + if (shape.IsAsciiRepresentation()) return length(shape); |
| // Attempt to flatten before accessing the string. It probably |
| // doesn't make Utf8Length faster, but it is very likely that |
| // the string will be accessed later (for example by WriteUtf8) |
| // so it's still a good idea. |
| - TryFlatten(); |
| + if (!IsFlat(shape)) { |
| + TryFlatten(shape); // shape is now no longer valid. |
| + } |
| Access<StringInputBuffer> buffer(&string_input_buffer); |
| buffer->Reset(0, this); |
| int result = 0; |
| @@ -2933,23 +2936,26 @@ |
| Vector<const char> String::ToAsciiVector() { |
| - ASSERT(IsAsciiRepresentation()); |
| - ASSERT(IsFlat()); |
| + StringShape shape(this); |
| + ASSERT(shape.IsAsciiRepresentation()); |
| + ASSERT(IsFlat(shape)); |
| int offset = 0; |
| - int length = this->length(); |
| - StringRepresentationTag string_tag = representation_tag(); |
| + int length = this->length(shape); |
| + StringRepresentationTag string_tag = shape.representation_tag(); |
| String* string = this; |
| if (string_tag == kSlicedStringTag) { |
| SlicedString* sliced = SlicedString::cast(string); |
| offset += sliced->start(); |
| - string = String::cast(sliced->buffer()); |
| - string_tag = string->representation_tag(); |
| + string = sliced->buffer(); |
| + shape = StringShape(string); |
| + string_tag = shape.representation_tag(); |
| } else if (string_tag == kConsStringTag) { |
| ConsString* cons = ConsString::cast(string); |
| - ASSERT(String::cast(cons->second())->length() == 0); |
| - string = String::cast(cons->first()); |
| - string_tag = string->representation_tag(); |
| + ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
| + string = cons->first(); |
| + shape = StringShape(string); |
| + string_tag = shape.representation_tag(); |
| } |
| if (string_tag == kSeqStringTag) { |
| SeqAsciiString* seq = SeqAsciiString::cast(string); |
| @@ -2964,23 +2970,26 @@ |
| Vector<const uc16> String::ToUC16Vector() { |
| - ASSERT(IsTwoByteStringRepresentation()); |
| - ASSERT(IsFlat()); |
| + StringShape shape(this); |
| + ASSERT(shape.IsTwoByteRepresentation()); |
| + ASSERT(IsFlat(shape)); |
| int offset = 0; |
| - int length = this->length(); |
| - StringRepresentationTag string_tag = representation_tag(); |
| + int length = this->length(shape); |
| + StringRepresentationTag string_tag = shape.representation_tag(); |
| String* string = this; |
| if (string_tag == kSlicedStringTag) { |
| SlicedString* sliced = SlicedString::cast(string); |
| offset += sliced->start(); |
| string = String::cast(sliced->buffer()); |
| - string_tag = string->representation_tag(); |
| + shape = StringShape(string); |
| + string_tag = shape.representation_tag(); |
| } else if (string_tag == kConsStringTag) { |
| ConsString* cons = ConsString::cast(string); |
| - ASSERT(String::cast(cons->second())->length() == 0); |
| - string = String::cast(cons->first()); |
| - string_tag = string->representation_tag(); |
| + ASSERT(cons->second()->length(StringShape(cons->second())) == 0); |
| + string = cons->first(); |
| + shape = StringShape(string); |
| + string_tag = shape.representation_tag(); |
| } |
| if (string_tag == kSeqStringTag) { |
| SeqTwoByteString* seq = SeqTwoByteString::cast(string); |
| @@ -3060,8 +3069,9 @@ |
| const uc16* String::GetTwoByteData(unsigned start) { |
| - ASSERT(!IsAsciiRepresentation()); |
| - switch (representation_tag()) { |
| + StringShape shape(this); |
| + ASSERT(!shape.IsAsciiRepresentation()); |
| + switch (shape.representation_tag()) { |
| case kSeqStringTag: |
| return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
| case kExternalStringTag: |
| @@ -3069,12 +3079,12 @@ |
| ExternalTwoByteStringGetData(start); |
| case kSlicedStringTag: { |
| SlicedString* sliced_string = SlicedString::cast(this); |
| - String* buffer = String::cast(sliced_string->buffer()); |
| - if (buffer->StringIsConsString()) { |
| - ConsString* cons_string = ConsString::cast(buffer); |
| + String* buffer = sliced_string->buffer(); |
| + if (StringShape(buffer).IsCons()) { |
| + ConsString* cs = ConsString::cast(buffer); |
| // Flattened string. |
| - ASSERT(String::cast(cons_string->second())->length() == 0); |
| - buffer = String::cast(cons_string->first()); |
| + ASSERT(cs->second()->length(StringShape(cs->second())) == 0); |
| + buffer = cs->first(); |
| } |
| return buffer->GetTwoByteData(start + sliced_string->start()); |
| } |
| @@ -3175,8 +3185,9 @@ |
| int offset_correction = 0; |
| while (true) { |
| - String* left = String::cast(current->first()); |
| - unsigned left_length = (unsigned)left->length(); |
| + String* left = current->first(); |
| + StringShape left_shape(left); |
| + unsigned left_length = (unsigned)left->length(left_shape); |
| if (left_length > offset && |
| (max_chars <= left_length - offset || |
| (rbb->capacity <= left_length - offset && |
| @@ -3188,7 +3199,7 @@ |
| // the point where we switch to the -IntoBuffer routines (below) in order |
| // to maximize the chances of delegating a big chunk of work to the |
| // efficient *AsciiStringReadBlock routines. |
| - if (left->StringIsConsString()) { |
| + if (left_shape.IsCons()) { |
| current = ConsString::cast(left); |
| continue; |
| } else { |
| @@ -3200,10 +3211,10 @@ |
| } else if (left_length <= offset) { |
| // Right hand side only - iterate unless we have reached the bottom of |
| // the cons tree. |
| - String* right = String::cast(current->second()); |
| + String* right = current->second(); |
| offset -= left_length; |
| offset_correction += left_length; |
| - if (right->StringIsConsString()) { |
| + if (StringShape(right).IsCons()) { |
| current = ConsString::cast(right); |
| continue; |
| } else { |
| @@ -3235,7 +3246,7 @@ |
| const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb, |
| unsigned* offset_ptr, |
| unsigned max_chars) { |
| - String* backing = String::cast(buffer()); |
| + String* backing = buffer(); |
| unsigned offset = start() + *offset_ptr; |
| unsigned length = backing->length(); |
| if (max_chars > length - offset) { |
| @@ -3353,9 +3364,10 @@ |
| rbb->remaining = 0; |
| return NULL; |
| } |
| - switch (input->representation_tag()) { |
| + StringShape shape(input); |
| + switch (shape.representation_tag()) { |
| case kSeqStringTag: |
| - if (input->is_ascii_representation()) { |
| + if (shape.IsAsciiRepresentation()) { |
| SeqAsciiString* str = SeqAsciiString::cast(input); |
| return str->SeqAsciiStringReadBlock(&rbb->remaining, |
| offset_ptr, |
| @@ -3376,7 +3388,7 @@ |
| offset_ptr, |
| max_chars); |
| case kExternalStringTag: |
| - if (input->is_ascii_representation()) { |
| + if (shape.IsAsciiRepresentation()) { |
| return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( |
| &rbb->remaining, |
| offset_ptr, |
| @@ -3415,12 +3427,13 @@ |
| ReadBlockBuffer* rbb, |
| unsigned* offset_ptr, |
| unsigned max_chars) { |
| - ASSERT(*offset_ptr <= (unsigned)input->length()); |
| + StringShape shape(input); |
| + ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| if (max_chars == 0) return; |
| - switch (input->representation_tag()) { |
| + switch (shape.representation_tag()) { |
| case kSeqStringTag: |
| - if (input->is_ascii_representation()) { |
| + if (shape.IsAsciiRepresentation()) { |
| SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, |
| offset_ptr, |
| max_chars); |
| @@ -3442,7 +3455,7 @@ |
| max_chars); |
| return; |
| case kExternalStringTag: |
| - if (input->is_ascii_representation()) { |
| + if (shape.IsAsciiRepresentation()) { |
| ExternalAsciiString::cast(input)-> |
| ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); |
| } else { |
| @@ -3466,11 +3479,12 @@ |
| unsigned capacity, |
| unsigned* remaining, |
| unsigned* offset_ptr) { |
| - ASSERT(*offset_ptr <= (unsigned)input->length()); |
| - unsigned chars = input->length() - *offset_ptr; |
| + StringShape shape(input); |
| + ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| + unsigned chars = input->length(shape) - *offset_ptr; |
| ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
| const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars); |
| - ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); |
| + ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
| *remaining = rbb.remaining; |
| return answer; |
| } |
| @@ -3481,13 +3495,14 @@ |
| unsigned capacity, |
| unsigned* remaining, |
| unsigned* offset_ptr) { |
| + StringShape shape(*raw_input); |
| Handle<String> input(raw_input); |
| - ASSERT(*offset_ptr <= (unsigned)input->length()); |
| - unsigned chars = input->length() - *offset_ptr; |
| + ASSERT(*offset_ptr <= (unsigned)input->length(shape)); |
| + unsigned chars = input->length(shape) - *offset_ptr; |
| if (chars > capacity) chars = capacity; |
| ReadBlockBuffer rbb(util_buffer, 0, capacity, 0); |
| ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars); |
| - ASSERT(rbb.remaining <= static_cast<unsigned>(input->length())); |
| + ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape))); |
| *remaining = rbb.remaining; |
| return rbb.util_buffer; |
| } |
| @@ -3506,13 +3521,14 @@ |
| int offset_correction = 0; |
| while (true) { |
| - String* left = String::cast(current->first()); |
| - unsigned left_length = (unsigned)left->length(); |
| + String* left = current->first(); |
| + StringShape left_shape(left); |
| + unsigned left_length = (unsigned)left->length(left_shape); |
| if (left_length > offset && |
| max_chars <= left_length - offset) { |
| // Left hand side only - iterate unless we have reached the bottom of |
| // the cons tree. |
| - if (left->StringIsConsString()) { |
| + if (left_shape.IsCons()) { |
| current = ConsString::cast(left); |
| continue; |
| } else { |
| @@ -3525,8 +3541,8 @@ |
| // the cons tree. |
| offset -= left_length; |
| offset_correction += left_length; |
| - String* right = String::cast(current->second()); |
| - if (right->StringIsConsString()) { |
| + String* right = current->second(); |
| + if (StringShape(right).IsCons()) { |
| current = ConsString::cast(right); |
| continue; |
| } else { |
| @@ -3558,7 +3574,7 @@ |
| void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, |
| unsigned* offset_ptr, |
| unsigned max_chars) { |
| - String* backing = String::cast(buffer()); |
| + String* backing = buffer(); |
| unsigned offset = start() + *offset_ptr; |
| unsigned length = backing->length(); |
| if (max_chars > length - offset) { |
| @@ -3578,24 +3594,29 @@ |
| ASSERT(index >= 0 && index < this->length()); |
| // Check for a flattened cons string |
| - if (String::cast(second())->length() == 0) { |
| - return String::cast(first())->Get(index); |
| + if (second()->length() == 0) { |
| + String* left = first(); |
| + return left->Get(StringShape(left), index); |
| } |
| String* string = String::cast(this); |
| + StringShape shape(string); |
| while (true) { |
| - if (string->StringIsConsString()) { |
| + if (shape.IsCons()) { |
| ConsString* cons_string = ConsString::cast(string); |
| - String* left = String::cast(cons_string->first()); |
| - if (left->length() > index) { |
| + String* left = cons_string->first(); |
| + StringShape left_shape(left); |
| + if (left->length(left_shape) > index) { |
| string = left; |
| + shape = left_shape; |
| } else { |
| - index -= left->length(); |
| - string = String::cast(cons_string->second()); |
| + index -= left->length(left_shape); |
| + string = cons_string->second(); |
| + shape = StringShape(string); |
| } |
| } else { |
| - return string->Get(index); |
| + return string->Get(shape, index); |
| } |
| } |
| @@ -3609,9 +3630,10 @@ |
| // SlicedStrings that are constructed directly on top of other |
| // SlicedStrings. |
| String* buf = String::cast(buffer()); |
| - ASSERT(!buf->StringIsSlicedString()); |
| - if (buf->StringIsConsString()) { |
| - Object* ok = buf->Flatten(); |
| + StringShape buf_shape(buf); |
| + ASSERT(!buf_shape.IsSliced()); |
| + if (buf_shape.IsCons()) { |
| + Object* ok = buf->Flatten(buf_shape); |
| if (ok->IsFailure()) return ok; |
| } |
| return this; |
| @@ -3620,15 +3642,17 @@ |
| template <typename sinkchar> |
| void String::WriteToFlat(String* src, |
| + StringShape src_shape, |
| sinkchar* sink, |
| int f, |
| int t) { |
| String* source = src; |
| + StringShape shape = src_shape; |
| int from = f; |
| int to = t; |
| while (true) { |
| - ASSERT(0 <= from && from <= to && to <= source->length()); |
| - switch (source->full_representation_tag()) { |
| + ASSERT(0 <= from && from <= to && to <= source->length(shape)); |
| + switch (shape.full_representation_tag()) { |
| case kAsciiStringTag | kExternalStringTag: { |
| CopyChars(sink, |
| ExternalAsciiString::cast(source)->resource()->data() + from, |
| @@ -3662,35 +3686,40 @@ |
| from += start; |
| to += start; |
| source = String::cast(sliced_string->buffer()); |
| + shape = StringShape(source); |
| break; |
| } |
| case kAsciiStringTag | kConsStringTag: |
| case kTwoByteStringTag | kConsStringTag: { |
| ConsString* cons_string = ConsString::cast(source); |
| - String* first = String::cast(cons_string->first()); |
| - int boundary = first->length(); |
| + String* first = cons_string->first(); |
| + StringShape first_shape(first); |
| + int boundary = first->length(first_shape); |
| if (to - boundary >= boundary - from) { |
| // Right hand side is longer. Recurse over left. |
| if (from < boundary) { |
| - WriteToFlat(first, sink, from, boundary); |
| + WriteToFlat(first, first_shape, sink, from, boundary); |
| sink += boundary - from; |
| from = 0; |
| } else { |
| from -= boundary; |
| } |
| to -= boundary; |
| - source = String::cast(cons_string->second()); |
| + source = cons_string->second(); |
| + shape = StringShape(source); |
| } else { |
| // Left hand side is longer. Recurse over right. |
| if (to > boundary) { |
| - String* second = String::cast(cons_string->second()); |
| + String* second = cons_string->second(); |
| WriteToFlat(second, |
| + StringShape(second), |
| sink + boundary - from, |
| 0, |
| to - boundary); |
| to = boundary; |
| } |
| source = first; |
| + shape = first_shape; |
| } |
| break; |
| } |
| @@ -3707,7 +3736,8 @@ |
| uint16_t SlicedString::SlicedStringGet(int index) { |
| ASSERT(index >= 0 && index < this->length()); |
| // Delegate to the buffer string. |
| - return String::cast(buffer())->Get(start() + index); |
| + String* underlying = buffer(); |
| + return underlying->Get(StringShape(underlying), start() + index); |
| } |
| @@ -3771,8 +3801,9 @@ |
| template <typename IteratorA> |
| static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { |
| - if (b->IsFlat()) { |
| - if (b->IsAsciiRepresentation()) { |
| + StringShape b_shape(b); |
| + if (b->IsFlat(b_shape)) { |
| + if (b_shape.IsAsciiRepresentation()) { |
| VectorIterator<char> ib(b->ToAsciiVector()); |
| return CompareStringContents(ia, &ib); |
| } else { |
| @@ -3789,10 +3820,12 @@ |
| static StringInputBuffer string_compare_buffer_a; |
| -bool String::SlowEquals(String* other) { |
| +bool String::SlowEquals(StringShape this_shape, |
| + String* other, |
| + StringShape other_shape) { |
| // Fast check: negative check with lengths. |
| - int len = length(); |
| - if (len != other->length()) return false; |
| + int len = length(this_shape); |
| + if (len != other->length(other_shape)) return false; |
| if (len == 0) return true; |
| // Fast check: if hash code is computed for both strings |
| @@ -3801,18 +3834,18 @@ |
| if (Hash() != other->Hash()) return false; |
| } |
| - if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) { |
| + if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) { |
| const char* str1 = SeqAsciiString::cast(this)->GetChars(); |
| const char* str2 = SeqAsciiString::cast(other)->GetChars(); |
| return CompareRawStringContents(Vector<const char>(str1, len), |
| Vector<const char>(str2, len)); |
| } |
| - if (this->IsFlat()) { |
| - if (this->IsAsciiRepresentation()) { |
| + if (this->IsFlat(this_shape)) { |
| + if (this_shape.IsAsciiRepresentation()) { |
| Vector<const char> vec1 = this->ToAsciiVector(); |
| - if (other->IsFlat()) { |
| - if (other->IsAsciiRepresentation()) { |
| + if (other->IsFlat(other_shape)) { |
| + if (other_shape.IsAsciiRepresentation()) { |
| Vector<const char> vec2 = other->ToAsciiVector(); |
| return CompareRawStringContents(vec1, vec2); |
| } else { |
| @@ -3827,8 +3860,8 @@ |
| } |
| } else { |
| Vector<const uc16> vec1 = this->ToUC16Vector(); |
| - if (other->IsFlat()) { |
| - if (other->IsAsciiRepresentation()) { |
| + if (other->IsFlat(other_shape)) { |
| + if (other_shape.IsAsciiRepresentation()) { |
| VectorIterator<uc16> buf1(vec1); |
| VectorIterator<char> ib(other->ToAsciiVector()); |
| return CompareStringContents(&buf1, &ib); |
| @@ -3850,7 +3883,8 @@ |
| bool String::MarkAsUndetectable() { |
| - if (this->IsSymbol()) return false; |
| + StringShape shape(this); |
| + if (shape.IsSymbol()) return false; |
| Map* map = this->map(); |
| if (map == Heap::short_string_map()) { |
| @@ -3878,13 +3912,14 @@ |
| bool String::IsEqualTo(Vector<const char> str) { |
| - int slen = length(); |
| + StringShape this_shape(this); |
| + int slen = length(this_shape); |
| Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); |
| decoder->Reset(str.start(), str.length()); |
| int i; |
| for (i = 0; i < slen && decoder->has_more(); i++) { |
| uc32 r = decoder->GetNext(); |
| - if (Get(i) != r) return false; |
| + if (Get(this_shape, i) != r) return false; |
| } |
| return i == slen && !decoder->has_more(); |
| } |
| @@ -3938,7 +3973,8 @@ |
| bool String::SlowAsArrayIndex(uint32_t* index) { |
| - if (length() <= kMaxCachedArrayIndexLength) { |
| + StringShape shape(this); |
| + if (length(shape) <= kMaxCachedArrayIndexLength) { |
| Hash(); // force computation of hash code |
| uint32_t field = length_field(); |
| if ((field & kIsArrayIndexMask) == 0) return false; |
| @@ -3946,7 +3982,7 @@ |
| return true; |
| } else { |
| StringInputBuffer buffer(this); |
| - return ComputeArrayIndex(&buffer, index, length()); |
| + return ComputeArrayIndex(&buffer, index, length(shape)); |
| } |
| } |
| @@ -4006,20 +4042,21 @@ |
| } |
| -Object* String::Slice(int start, int end) { |
| - if (start == 0 && end == length()) return this; |
| - int representation = representation_tag(); |
| - if (representation == kSlicedStringTag) { |
| +Object* String::Slice(StringShape shape, int start, int end) { |
| + if (start == 0 && end == length(shape)) return this; |
| + if (shape.representation_tag() == kSlicedStringTag) { |
| // Translate slices of a SlicedString into slices of the |
| // underlying string buffer. |
| SlicedString* str = SlicedString::cast(this); |
| - return Heap::AllocateSlicedString(String::cast(str->buffer()), |
| + String* buf = str->buffer(); |
| + return Heap::AllocateSlicedString(buf, |
| + StringShape(buf), |
| str->start() + start, |
| str->start() + end); |
| } |
| - Object* answer = Heap::AllocateSlicedString(this, start, end); |
| - if (answer->IsFailure()) { |
| - return answer; |
| + Object* result = Heap::AllocateSlicedString(this, shape, start, end); |
| + if (result->IsFailure()) { |
| + return result; |
| } |
| // Due to the way we retry after GC on allocation failure we are not allowed |
| // to fail on allocation after this point. This is the one-allocation rule. |
| @@ -4031,12 +4068,15 @@ |
| // will succeed often enough to avoid the problem. We only have to do this |
| // if Heap::AllocateSlicedString actually returned a SlicedString. It will |
| // return flat strings for small slices for efficiency reasons. |
| - if (String::cast(answer)->StringIsSlicedString() && |
| - representation == kConsStringTag) { |
| - TryFlatten(); |
| + String* answer = String::cast(result); |
| + StringShape answer_shape(answer); |
| + if (answer_shape.IsSliced() && |
| + shape.representation_tag() == kConsStringTag) { |
| + TryFlatten(shape); |
| // If the flatten succeeded we might as well make the sliced string point |
| // to the flat string rather than the cons string. |
| - if (String::cast(ConsString::cast(this)->second())->length() == 0) { |
| + String* second = ConsString::cast(this)->second(); |
| + if (second->length(StringShape(second)) == 0) { |
| SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first()); |
| } |
| } |
| @@ -4045,9 +4085,10 @@ |
| void String::PrintOn(FILE* file) { |
| - int length = this->length(); |
| + StringShape shape(this); |
| + int length = this->length(shape); |
| for (int i = 0; i < length; i++) { |
| - fprintf(file, "%c", Get(i)); |
| + fprintf(file, "%c", Get(shape, i)); |
| } |
| } |
| @@ -5532,12 +5573,13 @@ |
| Object* val = JSValue::cast(this)->value(); |
| if (val->IsString()) { |
| String* str = String::cast(val); |
| + StringShape shape(str); |
| if (storage) { |
| - for (int i = 0; i < str->length(); i++) { |
| + for (int i = 0; i < str->length(shape); i++) { |
| storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
| } |
| } |
| - counter += str->length(); |
| + counter += str->length(shape); |
| } |
| } |
| ASSERT(!storage || storage->length() == counter); |
| @@ -5722,11 +5764,12 @@ |
| Object* GetObject() { |
| // If the string is a cons string, attempt to flatten it so that |
| // symbols will most often be flat strings. |
| - if (string_->IsConsString()) { |
| + StringShape shape(string_); |
| + if (shape.IsCons()) { |
| ConsString* cons_string = ConsString::cast(string_); |
| - cons_string->TryFlatten(); |
| + cons_string->TryFlatten(shape); |
| if (cons_string->second() == Heap::empty_string()) { |
| - string_ = String::cast(cons_string->first()); |
| + string_ = cons_string->first(); |
| } |
| } |
| // Transform string to symbol if possible. |
| @@ -5884,7 +5927,7 @@ |
| return false; |
| } else { |
| String* result = String::cast(KeyAt(entry)); |
| - ASSERT(result->is_symbol()); |
| + ASSERT(StringShape(result).IsSymbol()); |
| *symbol = result; |
| return true; |
| } |