| Index: src/objects.cc | 
| diff --git a/src/objects.cc b/src/objects.cc | 
| index eeca17d433e31686cbbc838b7b9c4700807e6d9c..c75e6c8e7cc256039eadf660ff77ebe396cbec7e 100644 | 
| --- a/src/objects.cc | 
| +++ b/src/objects.cc | 
| @@ -1169,6 +1169,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size, | 
| case kConsStringTag: | 
| ConsString::BodyDescriptor::IterateBody(this, v); | 
| break; | 
| +      case kSlicedStringTag: | 
| +        SlicedString::BodyDescriptor::IterateBody(this, v); | 
| +        break; | 
| case kExternalStringTag: | 
| if ((type & kStringEncodingMask) == kAsciiStringTag) { | 
| reinterpret_cast<ExternalAsciiString*>(this)-> | 
| @@ -5230,7 +5233,10 @@ int String::Utf8Length() { | 
|  | 
|  | 
| Vector<const char> String::ToAsciiVector() { | 
| -  ASSERT(IsAsciiRepresentation()); | 
| +  // Either the string is sequential or external, in which case the encoding | 
| +  // needs to be ASCII, or the string is a cons or a slice, in which case the | 
| +  // encoding of the underlying string needs to be ASCII. | 
| +  ASSERT(IsAsciiRepresentationUnderneath()); | 
| ASSERT(IsFlat()); | 
|  | 
| int offset = 0; | 
| @@ -5242,21 +5248,33 @@ Vector<const char> String::ToAsciiVector() { | 
| ASSERT(cons->second()->length() == 0); | 
| string = cons->first(); | 
| string_tag = StringShape(string).representation_tag(); | 
| +    ASSERT(string_tag != kConsStringTag); | 
| +  } | 
| +  if (string_tag == kSlicedStringTag) { | 
| +    // Note that the parent of a slice cannot be a cons or a slice. | 
| +    SlicedString* slice = SlicedString::cast(string); | 
| +    offset = slice->offset(); | 
| +    string = slice->parent(); | 
| +    string_tag = StringShape(string).representation_tag(); | 
| +    ASSERT(string_tag != kConsStringTag && string_tag != kSlicedStringTag); | 
| } | 
| -  if (string_tag == kSeqStringTag) { | 
| -    SeqAsciiString* seq = SeqAsciiString::cast(string); | 
| -    char* start = seq->GetChars(); | 
| +  if (string_tag == kExternalStringTag) { | 
| +    ExternalAsciiString* ext = ExternalAsciiString::cast(string); | 
| +    const char* start = ext->resource()->data(); | 
| return Vector<const char>(start + offset, length); | 
| } | 
| -  ASSERT(string_tag == kExternalStringTag); | 
| -  ExternalAsciiString* ext = ExternalAsciiString::cast(string); | 
| -  const char* start = ext->resource()->data(); | 
| +  ASSERT(StringShape(string).representation_tag() == kSeqStringTag); | 
| +  SeqAsciiString* seq = SeqAsciiString::cast(string); | 
| +  char* start = seq->GetChars(); | 
| return Vector<const char>(start + offset, length); | 
| } | 
|  | 
|  | 
| Vector<const uc16> String::ToUC16Vector() { | 
| -  ASSERT(IsTwoByteRepresentation()); | 
| +  // Either the string is sequential or external, in which case the encoding | 
| +  // needs to be two-byte, or the string is a cons or a slice, in which case | 
| +  // the encoding of the underlying string needs to be two-byte. | 
| +  ASSERT(IsTwoByteRepresentationUnderneath()); | 
| ASSERT(IsFlat()); | 
|  | 
| int offset = 0; | 
| @@ -5268,16 +5286,25 @@ Vector<const uc16> String::ToUC16Vector() { | 
| ASSERT(cons->second()->length() == 0); | 
| string = cons->first(); | 
| string_tag = StringShape(string).representation_tag(); | 
| +    ASSERT(string_tag != kConsStringTag); | 
| +  } | 
| +  if (string_tag == kSlicedStringTag) { | 
| +    // Note that the parent of a slice cannot be a cons or a slice. | 
| +    SlicedString* slice = SlicedString::cast(string); | 
| +    offset = slice->offset(); | 
| +    string = slice->parent(); | 
| +    string_tag = StringShape(string).representation_tag(); | 
| +    ASSERT(string_tag != kConsStringTag && string_tag != kSlicedStringTag); | 
| } | 
| -  if (string_tag == kSeqStringTag) { | 
| -    SeqTwoByteString* seq = SeqTwoByteString::cast(string); | 
| -    return Vector<const uc16>(seq->GetChars() + offset, length); | 
| +  if (string_tag == kExternalStringTag) { | 
| +    ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); | 
| +    const uc16* start = | 
| +        reinterpret_cast<const uc16*>(ext->resource()->data()); | 
| +    return Vector<const uc16>(start + offset, length); | 
| } | 
| -  ASSERT(string_tag == kExternalStringTag); | 
| -  ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); | 
| -  const uc16* start = | 
| -      reinterpret_cast<const uc16*>(ext->resource()->data()); | 
| -  return Vector<const uc16>(start + offset, length); | 
| +  ASSERT(StringShape(string).representation_tag() == kSeqStringTag); | 
| +  SeqTwoByteString* seq = SeqTwoByteString::cast(string); | 
| +  return Vector<const uc16>(seq->GetChars() + offset, length); | 
| } | 
|  | 
|  | 
| @@ -5348,13 +5375,17 @@ const uc16* String::GetTwoByteData() { | 
|  | 
|  | 
| const uc16* String::GetTwoByteData(unsigned start) { | 
| -  ASSERT(!IsAsciiRepresentation()); | 
| +  ASSERT(!IsAsciiRepresentationUnderneath()); | 
| switch (StringShape(this).representation_tag()) { | 
| case kSeqStringTag: | 
| return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 
| case kExternalStringTag: | 
| return ExternalTwoByteString::cast(this)-> | 
| ExternalTwoByteStringGetData(start); | 
| +    case kSlicedStringTag: { | 
| +      SlicedString* slice = SlicedString::cast(this); | 
| +      return slice->parent()->GetTwoByteData(start + slice->offset()); | 
| +    } | 
| case kConsStringTag: | 
| UNREACHABLE(); | 
| return NULL; | 
| @@ -5645,6 +5676,10 @@ const unibrow::byte* String::ReadBlock(String* input, | 
| max_chars); | 
| return rbb->util_buffer; | 
| } | 
| +    case kSlicedStringTag: | 
| +      return SlicedString::cast(input)->SlicedStringReadBlock(rbb, | 
| +                                                              offset_ptr, | 
| +                                                              max_chars); | 
| default: | 
| break; | 
| } | 
| @@ -5786,6 +5821,11 @@ void String::ReadBlockIntoBuffer(String* input, | 
| max_chars); | 
| } | 
| return; | 
| +    case kSlicedStringTag: | 
| +      SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb, | 
| +                                                                 offset_ptr, | 
| +                                                                 max_chars); | 
| +      return; | 
| default: | 
| break; | 
| } | 
| @@ -5920,6 +5960,31 @@ uint16_t ConsString::ConsStringGet(int index) { | 
| } | 
|  | 
|  | 
| +uint16_t SlicedString::SlicedStringGet(int index) { | 
| +  return parent()->Get(offset() + index); | 
| +} | 
| + | 
| + | 
| +const unibrow::byte* SlicedString::SlicedStringReadBlock( | 
| +    ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) { | 
| +  unsigned offset = this->offset(); | 
| +  *offset_ptr += offset; | 
| +  const unibrow::byte* answer = String::ReadBlock(String::cast(parent()), | 
| +                                                  buffer, offset_ptr, chars); | 
| +  *offset_ptr -= offset; | 
| +  return answer; | 
| +} | 
| + | 
| + | 
| +void SlicedString::SlicedStringReadBlockIntoBuffer( | 
| +    ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) { | 
| +  unsigned offset = this->offset(); | 
| +  *offset_ptr += offset; | 
| +  String::ReadBlockIntoBuffer(String::cast(parent()), | 
| +                              buffer, offset_ptr, chars); | 
| +  *offset_ptr -= offset; | 
| +} | 
| + | 
| template <typename sinkchar> | 
| void String::WriteToFlat(String* src, | 
| sinkchar* sink, | 
| @@ -5987,6 +6052,13 @@ void String::WriteToFlat(String* src, | 
| } | 
| break; | 
| } | 
| +      case kAsciiStringTag | kSlicedStringTag: | 
| +      case kTwoByteStringTag | kSlicedStringTag: { | 
| +        SlicedString* slice = SlicedString::cast(source); | 
| +        unsigned offset = slice->offset(); | 
| +        WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 
| +        return; | 
| +      } | 
| } | 
| } | 
| } | 
|  |