int end = index + other_length < str_length ?
index + other_length :
str_length;
- Handle<String> slice =
- Factory::NewStringSlice(Handle<String>(str), index, end);
- return slice->IsEqualTo(Vector<const char>(other, other_length));
+ Handle<String> substring =
+ Factory::NewSubString(Handle<String>(str), index, end);
+ return substring->IsEqualTo(Vector<const char>(other, other_length));
}
}
-Handle<String> Factory::NewStringSlice(Handle<String> str,
- int begin,
- int end) {
- CALL_HEAP_FUNCTION(str->Slice(begin, end), String);
+Handle<String> Factory::NewSubString(Handle<String> str,
+ int begin,
+ int end) {
+ CALL_HEAP_FUNCTION(str->SubString(begin, end), String);
}
static Handle<String> NewConsString(Handle<String> first,
Handle<String> second);
- // Create a new sliced string object which represents a substring of a
- // backing string.
- static Handle<String> NewStringSlice(Handle<String> str,
- int begin,
- int end);
+ // Create a new string object which holds a substring of a string.
+ static Handle<String> NewSubString(Handle<String> str,
+ int begin,
+ int end);
// Creates a new external String object. There are two String encodings
// in the system: ASCII and two byte. Unlike other String types, it does
Handle<String> SubString(Handle<String> str, int start, int end) {
- CALL_HEAP_FUNCTION(str->Slice(start, end), String);
+ CALL_HEAP_FUNCTION(str->SubString(start, end), String);
}
Object* Heap::AllocateConsString(String* first, String* second) {
int first_length = first->length();
- if (first_length == 0) return second;
+ if (first_length == 0) {
+ return second;
+ }
int second_length = second->length();
- if (second_length == 0) return first;
+ if (second_length == 0) {
+ return first;
+ }
int length = first_length + second_length;
bool is_ascii = first->IsAsciiRepresentation()
}
-Object* Heap::AllocateSlicedString(String* buffer,
- int start,
- int end) {
- int length = end - start;
-
- // If the resulting string is small make a sub string.
- if (length <= String::kMinNonFlatLength) {
- return Heap::AllocateSubString(buffer, start, end);
- }
-
- Map* map;
- if (length <= String::kMaxShortSize) {
- map = buffer->IsAsciiRepresentation() ?
- short_sliced_ascii_string_map() :
- short_sliced_string_map();
- } else if (length <= String::kMaxMediumSize) {
- map = buffer->IsAsciiRepresentation() ?
- medium_sliced_ascii_string_map() :
- medium_sliced_string_map();
- } else {
- map = buffer->IsAsciiRepresentation() ?
- long_sliced_ascii_string_map() :
- long_sliced_string_map();
- }
-
- Object* result = Allocate(map, NEW_SPACE);
- if (result->IsFailure()) return result;
-
- SlicedString* sliced_string = SlicedString::cast(result);
- sliced_string->set_buffer(buffer);
- sliced_string->set_start(start);
- sliced_string->set_length(length);
-
- return result;
-}
-
-
Object* Heap::AllocateSubString(String* buffer,
int start,
int end) {
? AllocateRawAsciiString(length)
: AllocateRawTwoByteString(length);
if (result->IsFailure()) return result;
+ String* string_result = String::cast(result);
// Copy the characters into the new object.
- String* string_result = String::cast(result);
- StringHasher hasher(length);
- int i = 0;
- for (; i < length && hasher.is_array_index(); i++) {
- uc32 c = buffer->Get(start + i);
- hasher.AddCharacter(c);
- string_result->Set(i, c);
- }
- for (; i < length; i++) {
- uc32 c = buffer->Get(start + i);
- hasher.AddCharacterNoIndex(c);
- string_result->Set(i, c);
+ if (buffer->IsAsciiRepresentation()) {
+ ASSERT(string_result->IsAsciiRepresentation());
+ char* dest = SeqAsciiString::cast(string_result)->GetChars();
+ String::WriteToFlat(buffer, dest, start, end);
+ } else {
+ ASSERT(string_result->IsTwoByteRepresentation());
+ uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
+ String::WriteToFlat(buffer, dest, start, end);
}
- string_result->set_length_field(hasher.GetHashField());
+
return result;
}
return long_cons_ascii_symbol_map();
}
- if (map == short_sliced_string_map()) return short_sliced_symbol_map();
- if (map == medium_sliced_string_map()) return medium_sliced_symbol_map();
- if (map == long_sliced_string_map()) return long_sliced_symbol_map();
-
- if (map == short_sliced_ascii_string_map()) {
- return short_sliced_ascii_symbol_map();
- }
- if (map == medium_sliced_ascii_string_map()) {
- return medium_sliced_ascii_symbol_map();
- }
- if (map == long_sliced_ascii_string_map()) {
- return long_sliced_ascii_symbol_map();
- }
-
if (map == short_external_string_map()) {
return short_external_symbol_map();
}
V(Map, short_cons_ascii_symbol_map, ShortConsAsciiSymbolMap) \
V(Map, medium_cons_ascii_symbol_map, MediumConsAsciiSymbolMap) \
V(Map, long_cons_ascii_symbol_map, LongConsAsciiSymbolMap) \
- V(Map, short_sliced_symbol_map, ShortSlicedSymbolMap) \
- V(Map, medium_sliced_symbol_map, MediumSlicedSymbolMap) \
- V(Map, long_sliced_symbol_map, LongSlicedSymbolMap) \
- V(Map, short_sliced_ascii_symbol_map, ShortSlicedAsciiSymbolMap) \
- V(Map, medium_sliced_ascii_symbol_map, MediumSlicedAsciiSymbolMap) \
- V(Map, long_sliced_ascii_symbol_map, LongSlicedAsciiSymbolMap) \
V(Map, short_external_symbol_map, ShortExternalSymbolMap) \
V(Map, medium_external_symbol_map, MediumExternalSymbolMap) \
V(Map, long_external_symbol_map, LongExternalSymbolMap) \
V(Map, short_cons_ascii_string_map, ShortConsAsciiStringMap) \
V(Map, medium_cons_ascii_string_map, MediumConsAsciiStringMap) \
V(Map, long_cons_ascii_string_map, LongConsAsciiStringMap) \
- V(Map, short_sliced_string_map, ShortSlicedStringMap) \
- V(Map, medium_sliced_string_map, MediumSlicedStringMap) \
- V(Map, long_sliced_string_map, LongSlicedStringMap) \
- V(Map, short_sliced_ascii_string_map, ShortSlicedAsciiStringMap) \
- V(Map, medium_sliced_ascii_string_map, MediumSlicedAsciiStringMap) \
- V(Map, long_sliced_ascii_string_map, LongSlicedAsciiStringMap) \
V(Map, short_external_string_map, ShortExternalStringMap) \
V(Map, medium_external_string_map, MediumExternalStringMap) \
V(Map, long_external_string_map, LongExternalStringMap) \
// Please note this does not perform a garbage collection.
static Object* AllocateConsString(String* first, String* second);
- // Allocates a new sliced string object which is a slice of an underlying
- // string buffer stretching from the index start (inclusive) to the index
- // end (exclusive).
- // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
- // failed.
- // Please note this does not perform a garbage collection.
- static Object* AllocateSlicedString(String* buffer,
- int start,
- int end);
-
// Allocates a new sub string object which is a substring of an underlying
// string buffer stretching from the index start (inclusive) to the index
// end (exclusive).
// This generates code that performs a charCodeAt() call or returns
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
-// It can handle flat and sliced strings, 8 and 16 bit characters and
-// cons strings where the answer is found in the left hand branch of the
-// cons. The slow case will flatten the string, which will ensure that
-// the answer is in the left hand side the next time around.
+// It can handle flat, 8 and 16 bit characters and cons strings where the
+// answer is found in the left hand branch of the cons. The slow case will
+// flatten the string, which will ensure that the answer is in the left hand
+// side the next time around.
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
Comment(masm_, "[ GenerateFastCharCodeAt");
ASSERT(args->length() == 2);
Label slow_case;
Label end;
Label not_a_flat_string;
- Label a_cons_string;
Label try_again_with_new_string;
Label ascii_string;
Label got_char_code;
__ bind(¬_a_flat_string);
__ and_(temp.reg(), kStringRepresentationMask);
__ cmp(temp.reg(), kConsStringTag);
- __ j(equal, &a_cons_string);
- __ cmp(temp.reg(), kSlicedStringTag);
__ j(not_equal, &slow_case);
- // SlicedString.
- // Add the offset to the index and trigger the slow case on overflow.
- __ add(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset));
- __ j(overflow, &slow_case);
- // Getting the underlying string is done by running the cons string code.
-
// ConsString.
- __ bind(&a_cons_string);
- // Get the first of the two strings. Both sliced and cons strings
- // store their source string at the same offset.
- ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset);
+ // Get the first of the two strings.
__ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
__ jmp(&try_again_with_new_string);
void MarkCompactCollector::MarkSymbolTable() {
// Objects reachable from symbols are marked as live so as to ensure
// that if the symbol itself remains alive after GC for any reason,
- // and if it is a sliced string or a cons string backed by an
- // external string (even indirectly), then the external string does
- // not receive a weak reference callback.
+ // and if it is a cons string backed by an external string (even indirectly),
+ // then the external string does not receive a weak reference callback.
SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
// Mark the symbol table itself.
SetMark(symbol_table);
case SHORT_ASCII_SYMBOL_TYPE:
case MEDIUM_ASCII_SYMBOL_TYPE:
case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
- case SHORT_SLICED_SYMBOL_TYPE:
- case MEDIUM_SLICED_SYMBOL_TYPE:
- case LONG_SLICED_SYMBOL_TYPE: return "SLICED_SYMBOL";
- case SHORT_SLICED_ASCII_SYMBOL_TYPE:
- case MEDIUM_SLICED_ASCII_SYMBOL_TYPE:
- case LONG_SLICED_ASCII_SYMBOL_TYPE: return "SLICED_ASCII_SYMBOL";
case SHORT_CONS_SYMBOL_TYPE:
case MEDIUM_CONS_SYMBOL_TYPE:
case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
case SHORT_CONS_ASCII_STRING_TYPE:
case MEDIUM_CONS_ASCII_STRING_TYPE:
case LONG_CONS_ASCII_STRING_TYPE: return "CONS_STRING";
- case SHORT_SLICED_STRING_TYPE:
- case MEDIUM_SLICED_STRING_TYPE:
- case LONG_SLICED_STRING_TYPE:
- case SHORT_SLICED_ASCII_STRING_TYPE:
- case MEDIUM_SLICED_ASCII_STRING_TYPE:
- case LONG_SLICED_ASCII_STRING_TYPE: return "SLICED_STRING";
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
case MEDIUM_EXTERNAL_ASCII_STRING_TYPE:
case LONG_EXTERNAL_ASCII_STRING_TYPE:
}
-bool Object::IsSlicedString() {
- if (!IsString()) return false;
- return StringShape(String::cast(this)).IsSliced();
-}
-
-
StringShape::StringShape(String* str)
: type_(str->map()->instance_type()) {
set_valid();
bool String::IsAsciiRepresentation() {
uint32_t type = map()->instance_type();
- if ((type & kStringRepresentationMask) == kSlicedStringTag) {
- return SlicedString::cast(this)->buffer()->IsAsciiRepresentation();
- }
if ((type & kStringRepresentationMask) == kConsStringTag &&
ConsString::cast(this)->second()->length() == 0) {
return ConsString::cast(this)->first()->IsAsciiRepresentation();
bool String::IsTwoByteRepresentation() {
uint32_t type = map()->instance_type();
- if ((type & kStringRepresentationMask) == kSlicedStringTag) {
- return SlicedString::cast(this)->buffer()->IsTwoByteRepresentation();
- } else if ((type & kStringRepresentationMask) == kConsStringTag &&
+ if ((type & kStringRepresentationMask) == kConsStringTag &&
ConsString::cast(this)->second()->length() == 0) {
return ConsString::cast(this)->first()->IsTwoByteRepresentation();
}
}
-bool StringShape::IsSliced() {
- return (type_ & kStringRepresentationMask) == kSlicedStringTag;
-}
-
-
bool StringShape::IsExternal() {
return (type_ & kStringRepresentationMask) == kExternalStringTag;
}
CAST_ACCESSOR(SeqAsciiString)
CAST_ACCESSOR(SeqTwoByteString)
CAST_ACCESSOR(ConsString)
-CAST_ACCESSOR(SlicedString)
CAST_ACCESSOR(ExternalString)
CAST_ACCESSOR(ExternalAsciiString)
CAST_ACCESSOR(ExternalTwoByteString)
case kConsStringTag | kAsciiStringTag:
case kConsStringTag | kTwoByteStringTag:
return ConsString::cast(this)->ConsStringGet(index);
- case kSlicedStringTag | kAsciiStringTag:
- case kSlicedStringTag | kTwoByteStringTag:
- return SlicedString::cast(this)->SlicedStringGet(index);
case kExternalStringTag | kAsciiStringTag:
return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index);
case kExternalStringTag | kTwoByteStringTag:
// Only flattened strings have second part empty.
return second->length() == 0;
}
- case kSlicedStringTag: {
- StringRepresentationTag tag =
- StringShape(SlicedString::cast(this)->buffer()).representation_tag();
- return tag == kSeqStringTag || tag == kExternalStringTag;
- }
default:
return true;
}
}
-String* SlicedString::buffer() {
- return String::cast(READ_FIELD(this, kBufferOffset));
-}
-
-
-void SlicedString::set_buffer(String* buffer) {
- WRITE_FIELD(this, kBufferOffset, buffer);
- WRITE_BARRIER(this, kBufferOffset);
-}
-
-
-int SlicedString::start() {
- return READ_INT_FIELD(this, kStartOffset);
-}
-
-
-void SlicedString::set_start(int start) {
- WRITE_INT_FIELD(this, kStartOffset, start);
-}
-
-
ExternalAsciiString::Resource* ExternalAsciiString::resource() {
return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
}
#endif
switch (StringShape(this).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.
- String* buf = ss->buffer();
- ASSERT(!buf->IsSlicedString());
- Object* ok = buf->TryFlatten();
- if (ok->IsFailure()) return ok;
- // Under certain circumstances (TryFlattenIfNotFlat 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 (StringShape(String::cast(ok)).IsCons()) {
- ss->set_buffer(ConsString::cast(ok)->first());
- }
- return this;
- }
case kConsStringTag: {
ConsString* cs = ConsString::cast(this);
if (cs->second()->length() == 0) {
case kConsStringTag:
reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v);
break;
- case kSlicedStringTag:
- reinterpret_cast<SlicedString*>(this)->SlicedStringIterateBody(v);
- break;
case kExternalStringTag:
if ((type & kStringEncodingMask) == kAsciiStringTag) {
reinterpret_cast<ExternalAsciiString*>(this)->
int length = this->length();
StringRepresentationTag string_tag = StringShape(this).representation_tag();
String* string = this;
- if (string_tag == kSlicedStringTag) {
- SlicedString* sliced = SlicedString::cast(string);
- offset += sliced->start();
- string = sliced->buffer();
- string_tag = StringShape(string).representation_tag();
- } else if (string_tag == kConsStringTag) {
+ if (string_tag == kConsStringTag) {
ConsString* cons = ConsString::cast(string);
ASSERT(cons->second()->length() == 0);
string = cons->first();
int length = this->length();
StringRepresentationTag string_tag = StringShape(this).representation_tag();
String* string = this;
- if (string_tag == kSlicedStringTag) {
- SlicedString* sliced = SlicedString::cast(string);
- offset += sliced->start();
- string = String::cast(sliced->buffer());
- string_tag = StringShape(string).representation_tag();
- } else if (string_tag == kConsStringTag) {
+ if (string_tag == kConsStringTag) {
ConsString* cons = ConsString::cast(string);
ASSERT(cons->second()->length() == 0);
string = cons->first();
case kExternalStringTag:
return ExternalTwoByteString::cast(this)->
ExternalTwoByteStringGetData(start);
- case kSlicedStringTag: {
- SlicedString* sliced_string = SlicedString::cast(this);
- String* buffer = sliced_string->buffer();
- if (StringShape(buffer).IsCons()) {
- ConsString* cs = ConsString::cast(buffer);
- // Flattened string.
- ASSERT(cs->second()->length() == 0);
- buffer = cs->first();
- }
- return buffer->GetTwoByteData(start + sliced_string->start());
- }
case kConsStringTag:
UNREACHABLE();
return NULL;
}
-const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb,
- unsigned* offset_ptr,
- unsigned max_chars) {
- String* backing = buffer();
- unsigned offset = start() + *offset_ptr;
- unsigned length = backing->length();
- if (max_chars > length - offset) {
- max_chars = length - offset;
- }
- const unibrow::byte* answer =
- String::ReadBlock(backing, rbb, &offset, max_chars);
- *offset_ptr = offset - start();
- return answer;
-}
-
-
uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
ASSERT(index >= 0 && index < length());
return resource()->data()[index];
return ConsString::cast(input)->ConsStringReadBlock(rbb,
offset_ptr,
max_chars);
- case kSlicedStringTag:
- return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
- offset_ptr,
- max_chars);
case kExternalStringTag:
if (input->IsAsciiRepresentation()) {
return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
offset_ptr,
max_chars);
return;
- case kSlicedStringTag:
- SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
- offset_ptr,
- max_chars);
- return;
case kExternalStringTag:
if (input->IsAsciiRepresentation()) {
ExternalAsciiString::cast(input)->
}
-void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
- unsigned* offset_ptr,
- unsigned max_chars) {
- String* backing = buffer();
- unsigned offset = start() + *offset_ptr;
- unsigned length = backing->length();
- if (max_chars > length - offset) {
- max_chars = length - offset;
- }
- String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars);
- *offset_ptr = offset - start();
-}
-
-
void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize);
}
to - from);
return;
}
- case kAsciiStringTag | kSlicedStringTag:
- case kTwoByteStringTag | kSlicedStringTag: {
- SlicedString* sliced_string = SlicedString::cast(source);
- int start = sliced_string->start();
- from += start;
- to += start;
- source = String::cast(sliced_string->buffer());
- break;
- }
case kAsciiStringTag | kConsStringTag:
case kTwoByteStringTag | kConsStringTag: {
ConsString* cons_string = ConsString::cast(source);
}
-void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) {
- IteratePointer(v, kBufferOffset);
-}
-
#define FIELD_ADDR(p, offset) \
(reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
#undef FIELD_ADDR
-uint16_t SlicedString::SlicedStringGet(int index) {
- ASSERT(index >= 0 && index < this->length());
- // Delegate to the buffer string.
- String* underlying = buffer();
- return underlying->Get(start() + index);
-}
-
-
template <typename IteratorA, typename IteratorB>
static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
// General slow case check. We know that the ia and ib iterators
}
-Object* String::Slice(int start, int end) {
+Object* String::SubString(int start, int end) {
if (start == 0 && end == length()) return this;
- if (StringShape(this).representation_tag() == kSlicedStringTag) {
- // Translate slices of a SlicedString into slices of the
- // underlying string buffer.
- SlicedString* str = SlicedString::cast(this);
- String* buf = str->buffer();
- return Heap::AllocateSlicedString(buf,
- str->start() + start,
- str->start() + end);
- }
- Object* result = Heap::AllocateSlicedString(this, 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.
-
- // Try to flatten a cons string that is under the sliced string.
- // This is to avoid memory leaks and possible stack overflows caused by
- // building 'towers' of sliced strings on cons strings.
- // This may fail due to an allocation failure (when a GC is needed), but it
- // 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.
- String* answer = String::cast(result);
- if (StringShape(answer).IsSliced() &&
- StringShape(this).representation_tag() == kConsStringTag) {
- TryFlatten();
- // If the flatten succeeded we might as well make the sliced string point
- // to the flat string rather than the cons string.
- String* second = ConsString::cast(this)->second();
- if (second->length() == 0) {
- SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
- }
- }
- return answer;
+ Object* result = Heap::AllocateSubString(this, start, end);
+ return result;
}
return;
}
- // Get the slice of the source for this function.
+ // Get the source for the script which this function came from.
// Don't use String::cast because we don't want more assertion errors while
// we are already creating a stack dump.
String* script_source =
// - SeqAsciiString
// - SeqTwoByteString
// - ConsString
-// - SlicedString
// - ExternalString
// - ExternalAsciiString
// - ExternalTwoByteString
// considered TWO_BYTE. It is not mentioned in the name. ASCII encoding is
// mentioned explicitly in the name. Likewise, the default representation is
// considered sequential. It is not mentioned in the name. The other
-// representations (eg, CONS, SLICED, EXTERNAL) are explicitly mentioned.
+// representations (eg, CONS, EXTERNAL) are explicitly mentioned.
// Finally, the string is either a SYMBOL_TYPE (if it is a symbol) or a
// STRING_TYPE (if it is not a symbol).
//
V(SHORT_CONS_ASCII_SYMBOL_TYPE) \
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE) \
V(LONG_CONS_ASCII_SYMBOL_TYPE) \
- V(SHORT_SLICED_SYMBOL_TYPE) \
- V(MEDIUM_SLICED_SYMBOL_TYPE) \
- V(LONG_SLICED_SYMBOL_TYPE) \
- V(SHORT_SLICED_ASCII_SYMBOL_TYPE) \
- V(MEDIUM_SLICED_ASCII_SYMBOL_TYPE) \
- V(LONG_SLICED_ASCII_SYMBOL_TYPE) \
V(SHORT_EXTERNAL_SYMBOL_TYPE) \
V(MEDIUM_EXTERNAL_SYMBOL_TYPE) \
V(LONG_EXTERNAL_SYMBOL_TYPE) \
V(SHORT_CONS_ASCII_STRING_TYPE) \
V(MEDIUM_CONS_ASCII_STRING_TYPE) \
V(LONG_CONS_ASCII_STRING_TYPE) \
- V(SHORT_SLICED_STRING_TYPE) \
- V(MEDIUM_SLICED_STRING_TYPE) \
- V(LONG_SLICED_STRING_TYPE) \
- V(SHORT_SLICED_ASCII_STRING_TYPE) \
- V(MEDIUM_SLICED_ASCII_STRING_TYPE) \
- V(LONG_SLICED_ASCII_STRING_TYPE) \
V(SHORT_EXTERNAL_STRING_TYPE) \
V(MEDIUM_EXTERNAL_STRING_TYPE) \
V(LONG_EXTERNAL_STRING_TYPE) \
ConsString::kSize, \
long_cons_ascii_symbol, \
LongConsAsciiSymbol) \
- V(SHORT_SLICED_SYMBOL_TYPE, \
- SlicedString::kSize, \
- short_sliced_symbol, \
- ShortSlicedSymbol) \
- V(MEDIUM_SLICED_SYMBOL_TYPE, \
- SlicedString::kSize, \
- medium_sliced_symbol, \
- MediumSlicedSymbol) \
- V(LONG_SLICED_SYMBOL_TYPE, \
- SlicedString::kSize, \
- long_sliced_symbol, \
- LongSlicedSymbol) \
- V(SHORT_SLICED_ASCII_SYMBOL_TYPE, \
- SlicedString::kSize, \
- short_sliced_ascii_symbol, \
- ShortSlicedAsciiSymbol) \
- V(MEDIUM_SLICED_ASCII_SYMBOL_TYPE, \
- SlicedString::kSize, \
- medium_sliced_ascii_symbol, \
- MediumSlicedAsciiSymbol) \
- V(LONG_SLICED_ASCII_SYMBOL_TYPE, \
- SlicedString::kSize, \
- long_sliced_ascii_symbol, \
- LongSlicedAsciiSymbol) \
V(SHORT_EXTERNAL_SYMBOL_TYPE, \
ExternalTwoByteString::kSize, \
short_external_symbol, \
ConsString::kSize, \
long_cons_ascii_string, \
LongConsAsciiString) \
- V(SHORT_SLICED_STRING_TYPE, \
- SlicedString::kSize, \
- short_sliced_string, \
- ShortSlicedString) \
- V(MEDIUM_SLICED_STRING_TYPE, \
- SlicedString::kSize, \
- medium_sliced_string, \
- MediumSlicedString) \
- V(LONG_SLICED_STRING_TYPE, \
- SlicedString::kSize, \
- long_sliced_string, \
- LongSlicedString) \
- V(SHORT_SLICED_ASCII_STRING_TYPE, \
- SlicedString::kSize, \
- short_sliced_ascii_string, \
- ShortSlicedAsciiString) \
- V(MEDIUM_SLICED_ASCII_STRING_TYPE, \
- SlicedString::kSize, \
- medium_sliced_ascii_string, \
- MediumSlicedAsciiString) \
- V(LONG_SLICED_ASCII_STRING_TYPE, \
- SlicedString::kSize, \
- long_sliced_ascii_string, \
- LongSlicedAsciiString) \
V(SHORT_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kSize, \
short_external_string, \
enum StringRepresentationTag {
kSeqStringTag = 0x0,
kConsStringTag = 0x1,
- kSlicedStringTag = 0x2,
kExternalStringTag = 0x3
};
kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
LONG_CONS_ASCII_SYMBOL_TYPE =
kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
- SHORT_SLICED_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSlicedStringTag,
- MEDIUM_SLICED_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSlicedStringTag,
- LONG_SLICED_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSlicedStringTag,
- SHORT_SLICED_ASCII_SYMBOL_TYPE =
- kShortStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
- MEDIUM_SLICED_ASCII_SYMBOL_TYPE =
- kMediumStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
- LONG_SLICED_ASCII_SYMBOL_TYPE =
- kLongStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
SHORT_EXTERNAL_SYMBOL_TYPE =
kShortStringTag | kSymbolTag | kExternalStringTag,
MEDIUM_EXTERNAL_SYMBOL_TYPE =
kMediumStringTag | kAsciiStringTag | kConsStringTag,
LONG_CONS_ASCII_STRING_TYPE =
kLongStringTag | kAsciiStringTag | kConsStringTag,
- SHORT_SLICED_STRING_TYPE = kShortStringTag | kSlicedStringTag,
- MEDIUM_SLICED_STRING_TYPE = kMediumStringTag | kSlicedStringTag,
- LONG_SLICED_STRING_TYPE = kLongStringTag | kSlicedStringTag,
- SHORT_SLICED_ASCII_STRING_TYPE =
- kShortStringTag | kAsciiStringTag | kSlicedStringTag,
- MEDIUM_SLICED_ASCII_STRING_TYPE =
- kMediumStringTag | kAsciiStringTag | kSlicedStringTag,
- LONG_SLICED_ASCII_STRING_TYPE =
- kLongStringTag | kAsciiStringTag | kSlicedStringTag,
SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
inline bool IsSymbol();
// See objects-inl.h for more details
inline bool IsSeqString();
- inline bool IsSlicedString();
inline bool IsExternalString();
inline bool IsExternalTwoByteString();
inline bool IsExternalAsciiString();
inline bool IsSequential();
inline bool IsExternal();
inline bool IsCons();
- inline bool IsSliced();
inline bool IsExternalAscii();
inline bool IsExternalTwoByte();
inline bool IsSequentialAscii();
inline uint16_t Get(int index);
// Try to flatten the top level ConsString that is hiding behind this
- // string. This is a no-op unless the string is a ConsString or a
- // SlicedString. Flatten mutates the ConsString and might return a
- // failure.
+ // string. This is a no-op unless the string is a ConsString. Flatten
+ // mutates the ConsString and might return a failure.
Object* TryFlatten();
// Try to flatten the string. Checks first inline to see if it is necessary.
// ascii and two byte string types.
bool MarkAsUndetectable();
- // Slice the string and return a substring.
- Object* Slice(int from, int to);
+ // Return a substring.
+ Object* SubString(int from, int to);
// String equality operations.
inline bool Equals(String* other);
static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar;
static const int kMaxUC16CharCode = 0xffff;
- // Minimum length for a cons or sliced string.
+ // Minimum length for a cons string.
static const int kMinNonFlatLength = 13;
// Mask constant for checking if a string has a computed hash code
unsigned remaining;
};
- // NOTE: If you call StringInputBuffer routines on strings that are
- // too deeply nested trees of cons and slice strings, then this
- // routine will overflow the stack. Strings that are merely deeply
- // nested trees of cons strings do not have a problem apart from
- // performance.
-
static inline const unibrow::byte* ReadBlock(String* input,
ReadBlockBuffer* buffer,
unsigned* offset,
};
-// The SlicedString class describes string values that are slices of
-// some other string. SlicedStrings consist of a reference to an
-// underlying heap-allocated string value, a start index, and the
-// length field common to all strings.
-class SlicedString: public String {
- public:
- // The underlying string buffer.
- inline String* buffer();
- inline void set_buffer(String* buffer);
-
- // The start index of the slice.
- inline int start();
- inline void set_start(int start);
-
- // Dispatched behavior.
- uint16_t SlicedStringGet(int index);
-
- // Casting.
- static inline SlicedString* cast(Object* obj);
-
- // Garbage collection support.
- void SlicedStringIterateBody(ObjectVisitor* v);
-
- // Layout description
-#if V8_HOST_ARCH_64_BIT
- // Optimizations expect buffer to be located at same offset as a ConsString's
- // first substring. In 64 bit mode we have room for the start offset before
- // the buffer.
- static const int kStartOffset = String::kSize;
- static const int kBufferOffset = kStartOffset + kIntSize;
- static const int kSize = kBufferOffset + kPointerSize;
-#else
- static const int kBufferOffset = String::kSize;
- static const int kStartOffset = kBufferOffset + kPointerSize;
- static const int kSize = kStartOffset + kIntSize;
-#endif
-
- // Support for StringInputBuffer.
- inline const unibrow::byte* SlicedStringReadBlock(ReadBlockBuffer* buffer,
- unsigned* offset_ptr,
- unsigned chars);
- inline void SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
- unsigned* offset_ptr,
- unsigned chars);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(SlicedString);
-};
-
-
// The ExternalString class describes string values that are backed by
// a string resource that lies outside the V8 heap. ExternalStrings
// consist of the length field common to all strings, a pointer to the
if (StringShape(subject_ptr).IsCons()) {
subject_ptr = ConsString::cast(subject_ptr)->first();
- } else if (StringShape(subject_ptr).IsSliced()) {
- SlicedString* slice = SlicedString::cast(subject_ptr);
- start_offset += slice->start();
- end_offset += slice->start();
- subject_ptr = slice->buffer();
}
// Ensure that an underlying string has the same ascii-ness.
ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii);
capture_count,
subject_length);
}
- // Find substrings of replacement string and create them as String objects..
+ // Find substrings of replacement string and create them as String objects.
int substring_index = 0;
for (int i = 0, n = parts_.length(); i < n; i++) {
int tag = parts_[i].tag;
if (tag <= 0) { // A replacement string slice.
int from = -tag;
int to = parts_[i].data;
- replacement_substrings_.Add(Factory::NewStringSlice(replacement,
- from,
- to));
+ replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
parts_[i].tag = REPLACEMENT_SUBSTRING;
parts_[i].data = substring_index;
substring_index++;
}
-static Object* Runtime_StringSlice(Arguments args) {
+static Object* Runtime_SubString(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
RUNTIME_ASSERT(end >= start);
RUNTIME_ASSERT(start >= 0);
RUNTIME_ASSERT(end <= value->length());
- return value->Slice(start, end);
+ return value->SubString(start, end);
}
for (int i = 0; i < matches ; i++) {
int from = offsets.at(i * 2);
int to = offsets.at(i * 2 + 1);
- elements->set(i, *Factory::NewStringSlice(subject, from, to));
+ elements->set(i, *Factory::NewSubString(subject, from, to));
}
Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(matches));
right--;
}
}
- return s->Slice(left, right);
+ return s->SubString(left, right);
}
bool Runtime::IsUpperCaseChar(uint16_t ch) {
F(StringIndexOf, 3, 1) \
F(StringLastIndexOf, 3, 1) \
F(StringLocaleCompare, 2, 1) \
- F(StringSlice, 3, 1) \
+ F(SubString, 3, 1) \
F(StringReplaceRegExpWithString, 4, 1) \
F(StringMatch, 3, 1) \
F(StringTrim, 3, 1) \
}
return %CharFromCode(char_code);
}
- return %StringSlice(string, start, end);
+ return %SubString(string, start, end);
}
Label slow_case;
Label end;
Label not_a_flat_string;
- Label a_cons_string;
Label try_again_with_new_string;
Label ascii_string;
Label got_char_code;
__ bind(¬_a_flat_string);
__ and_(temp.reg(), Immediate(kStringRepresentationMask));
__ cmpb(temp.reg(), Immediate(kConsStringTag));
- __ j(equal, &a_cons_string);
- __ cmpb(temp.reg(), Immediate(kSlicedStringTag));
__ j(not_equal, &slow_case);
- // SlicedString.
- // Add the offset to the index and trigger the slow case on overflow.
- __ addl(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset));
- __ j(overflow, &slow_case);
- // Getting the underlying string is done by running the cons string code.
-
// ConsString.
- __ bind(&a_cons_string);
- // Get the first of the two strings. Both sliced and cons strings
- // store their source string at the same offset.
- ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset);
+ // Get the first of the two strings.
__ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
__ jmp(&try_again_with_new_string);
printf("6\n");
TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536);
printf("7\n");
- Handle<String> right_deep_slice =
- Factory::NewStringSlice(left_deep_asymmetric,
- left_deep_asymmetric->length() - 1050,
- left_deep_asymmetric->length() - 50);
- Handle<String> left_deep_slice =
- Factory::NewStringSlice(right_deep_asymmetric,
- right_deep_asymmetric->length() - 1050,
- right_deep_asymmetric->length() - 50);
- printf("8\n");
- Traverse(right_deep_slice, left_deep_slice);
- printf("9\n");
FlattenString(left_asymmetric);
printf("10\n");
Traverse(flat, left_asymmetric);
}
-static Handle<String> SliceOf(Handle<String> underlying) {
- int start = gen() % underlying->length();
- int end = start + gen() % (underlying->length() - start);
- return Factory::NewStringSlice(underlying,
- start,
- end);
-}
-
-
-static Handle<String> ConstructSliceTree(
- Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
- int from,
- int to) {
- CHECK(to > from);
- if (to - from <= 1)
- return SliceOf(building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]);
- if (to - from == 2) {
- Handle<String> lhs = building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
- if (gen() % 2 == 0)
- lhs = SliceOf(lhs);
- Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
- if (gen() % 2 == 0)
- rhs = SliceOf(rhs);
- return Factory::NewConsString(lhs, rhs);
- }
- Handle<String> part1 =
- ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
- Handle<String> part2 =
- ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
- Handle<String> branch = Factory::NewConsString(part1, part2);
- if (gen() % 2 == 0)
- return branch;
- return(SliceOf(branch));
-}
-
-
-TEST(Slice) {
- printf("TestSlice\n");
- InitializeVM();
- v8::HandleScope scope;
- Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
- ZoneScope zone(DELETE_ON_EXIT);
- InitializeBuildingBlocks(building_blocks);
-
- seed = 42;
- Handle<String> slice_tree =
- ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
- seed = 42;
- Handle<String> flat_slice_tree =
- ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
- FlattenString(flat_slice_tree);
- Traverse(flat_slice_tree, slice_tree);
-}
-
static const int DEEP_ASCII_DEPTH = 100000;
size_t length_;
bool* destructed_;
};
-
-
-// Regression test case for http://crbug.com/9746. The problem was
-// that when we marked objects reachable only through weak pointers,
-// we ended up keeping a sliced symbol alive, even though we already
-// invoked the weak callback on the underlying external string thus
-// deleting its resource.
-TEST(Regress9746) {
- InitializeVM();
-
- // Setup lengths that guarantee we'll get slices instead of simple
- // flat strings.
- static const int kFullStringLength = String::kMinNonFlatLength * 2;
- static const int kSliceStringLength = String::kMinNonFlatLength + 1;
-
- uint16_t* source = new uint16_t[kFullStringLength];
- for (int i = 0; i < kFullStringLength; i++) source[i] = '1';
- char* key = new char[kSliceStringLength];
- for (int i = 0; i < kSliceStringLength; i++) key[i] = '1';
- Vector<const char> key_vector(key, kSliceStringLength);
-
- // Allocate an external string resource that keeps track of when it
- // is destructed.
- bool resource_destructed = false;
- TwoByteResource* resource =
- new TwoByteResource(source, kFullStringLength, &resource_destructed);
-
- {
- v8::HandleScope scope;
-
- // Allocate an external string resource and external string. We
- // have to go through the API to get the weak handle and the
- // automatic destruction going.
- Handle<String> string =
- v8::Utils::OpenHandle(*v8::String::NewExternal(resource));
-
- // Create a slice of the external string.
- Handle<String> slice =
- Factory::NewStringSlice(string, 0, kSliceStringLength);
- CHECK_EQ(kSliceStringLength, slice->length());
- CHECK(StringShape(*slice).IsSliced());
-
- // Make sure the slice ends up in old space so we can morph it
- // into a symbol.
- while (Heap::InNewSpace(*slice)) {
- Heap::PerformScavenge();
- }
-
- // Force the slice into the symbol table.
- slice = Factory::SymbolFromString(slice);
- CHECK(slice->IsSymbol());
- CHECK(StringShape(*slice).IsSliced());
-
- Handle<String> buffer(Handle<SlicedString>::cast(slice)->buffer());
- CHECK(StringShape(*buffer).IsExternal());
- CHECK(buffer->IsTwoByteRepresentation());
-
- // Finally, base a script on the slice of the external string and
- // get its wrapper. This allocates yet another weak handle that
- // indirectly refers to the external string.
- Handle<Script> script = Factory::NewScript(slice);
- Handle<JSObject> wrapper = GetScriptWrapper(script);
- }
-
- // When we collect all garbage, we cannot get rid of the sliced
- // symbol entry in the symbol table because it is used by the script
- // kept alive by the weak wrapper. Make sure we don't destruct the
- // external string.
- Heap::CollectAllGarbage(false);
- CHECK(!resource_destructed);
-
- {
- v8::HandleScope scope;
-
- // Make sure the sliced symbol is still in the table.
- Handle<String> symbol = Factory::LookupSymbol(key_vector);
- CHECK(StringShape(*symbol).IsSliced());
-
- // Make sure the buffer is still a two-byte external string.
- Handle<String> buffer(Handle<SlicedString>::cast(symbol)->buffer());
- CHECK(StringShape(*buffer).IsExternal());
- CHECK(buffer->IsTwoByteRepresentation());
- }
-
- // Forcing another garbage collection should let us get rid of the
- // slice from the symbol table. The external string remains in the
- // heap until the next GC.
- Heap::CollectAllGarbage(false);
- CHECK(!resource_destructed);
- v8::HandleScope scope;
- Handle<String> key_string = Factory::NewStringFromAscii(key_vector);
- String* out;
- CHECK(!Heap::LookupSymbolIfExists(*key_string, &out));
-
- // Forcing yet another garbage collection must allow us to finally
- // get rid of the external string.
- Heap::CollectAllGarbage(false);
- CHECK(resource_destructed);
-
- delete[] source;
- delete[] key;
-}