Commit eca89dc7 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Create an abstraction for the string type flags so that they can be cached.

Read the objects.h change first to understand what's going on here.
Review URL: http://codereview.chromium.org/9038

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@675 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ec3c4ced
......@@ -2036,7 +2036,7 @@ int String::WriteAscii(char* buffer, int start, int length) {
i::Handle<i::String> str = Utils::OpenHandle(this);
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
str->TryFlatten();
str->TryFlatten(i::StringShape(*str));
int end = length;
if ( (length == -1) || (length > str->length() - start) )
end = str->length() - start;
......@@ -2061,7 +2061,7 @@ int String::Write(uint16_t* buffer, int start, int length) {
i::Handle<i::String> str = Utils::OpenHandle(this);
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
str->TryFlatten();
str->TryFlatten(i::StringShape(*str));
int end = length;
if ( (length == -1) || (length > str->length() - start) )
end = str->length() - start;
......@@ -2079,14 +2079,16 @@ int String::Write(uint16_t* buffer, int start, int length) {
bool v8::String::IsExternal() {
EnsureInitialized("v8::String::IsExternal()");
i::Handle<i::String> str = Utils::OpenHandle(this);
return str->IsExternalTwoByteString();
i::StringShape shape(*str);
return shape.IsExternalTwoByte();
}
bool v8::String::IsExternalAscii() {
EnsureInitialized("v8::String::IsExternalAscii()");
i::Handle<i::String> str = Utils::OpenHandle(this);
return str->IsExternalAsciiString();
i::StringShape shape(*str);
return shape.IsExternalAscii();
}
......
......@@ -840,7 +840,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
// function and insert it into the cache.
if (!cache->Lookup(name, &boilerplate)) {
#ifdef DEBUG
ASSERT(source->IsAsciiRepresentation());
ASSERT(StringShape(*source).IsAsciiRepresentation());
#endif
Handle<String> script_name = Factory::NewStringFromUtf8(name);
boilerplate =
......
......@@ -330,12 +330,14 @@ bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
{&v8::internal::CodeGenerator::GenerateObjectEquals,
"_ObjectEquals"}
};
if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
Handle<String> name = node->name();
StringShape shape(*name);
if (name->length(shape) > 0 && name->Get(shape, 0) == '_') {
for (unsigned i = 0;
i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
i++) {
const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
if (node->name()->IsEqualTo(CStrVector(entry->name))) {
if (name->IsEqualTo(CStrVector(entry->name))) {
((*this).*(entry->method))(args);
return true;
}
......
......@@ -157,8 +157,9 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
int line_offset, int column_offset,
v8::Extension* extension,
ScriptDataImpl* input_pre_data) {
Counters::total_load_size.Increment(source->length());
Counters::total_compile_size.Increment(source->length());
int source_length = source->length();
Counters::total_load_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length);
// The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER);
......@@ -175,7 +176,7 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
if (result.is_null()) {
// No cache entry found. Do pre-parsing and compile the script.
ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL && source->length() >= FLAG_min_preparse_length) {
if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
buf->Reset(source.location());
pre_data = PreParse(buf.value(), extension);
......@@ -208,8 +209,10 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
int line_offset,
bool is_global) {
Counters::total_eval_size.Increment(source->length());
Counters::total_compile_size.Increment(source->length());
StringShape source_shape(*source);
int source_length = source->length(source_shape);
Counters::total_eval_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length);
// The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER);
......
......@@ -55,7 +55,8 @@ static inline int GetChar(const char* str, int index) {
static inline int GetChar(String* str, int index) {
return str->Get(index);
StringShape shape(str);
return str->Get(shape, index);
}
......@@ -75,15 +76,18 @@ static inline const char* GetCString(const char* str, int index) {
static inline const char* GetCString(String* str, int index) {
char* result = NewArray<char>(str->length() + 1);
for (int i = index; i < str->length(); i++) {
if (str->Get(i) <= 127) {
result[i - index] = static_cast<char>(str->Get(i));
StringShape shape(str);
int length = str->length(shape);
char* result = NewArray<char>(length + 1);
for (int i = index; i < length; i++) {
uc16 c = str->Get(shape, i);
if (c <= 127) {
result[i - index] = static_cast<char>(c);
} else {
result[i - index] = 127; // Force number parsing to fail.
}
}
result[str->length() - index] = '\0';
result[length - index] = '\0';
return result;
}
......@@ -104,7 +108,8 @@ static inline bool IsSpace(const char* str, int index) {
static inline bool IsSpace(String* str, int index) {
return Scanner::kIsWhiteSpace.get(str->Get(index));
StringShape shape(str);
return Scanner::kIsWhiteSpace.get(str->Get(shape, index));
}
......@@ -116,12 +121,16 @@ static inline bool SubStringEquals(const char* str,
static inline bool SubStringEquals(String* str, int index, const char* other) {
StringShape shape(str);
HandleScope scope;
int len = strlen(other);
int end = index + len < str->length() ? index + len : str->length();
int str_length = str->length(shape);
int other_length = strlen(other);
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, len));
Factory::NewStringSlice(Handle<String>(str), shape, index, end);
return slice->IsEqualTo(Vector<const char>(other, other_length));
}
......
......@@ -90,15 +90,24 @@ Handle<String> Factory::NewRawTwoByteString(int length,
Handle<String> Factory::NewConsString(Handle<String> first,
Handle<String> second) {
if (first->length() == 0) return second;
if (second->length() == 0) return first;
CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
}
Handle<String> Factory::NewStringSlice(Handle<String> str, int begin, int end) {
CALL_HEAP_FUNCTION(str->Slice(begin, end), String);
StringShape first_shape,
Handle<String> second,
StringShape second_shape) {
if (first->length(first_shape) == 0) return second;
if (second->length(second_shape) == 0) return first;
CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first,
first_shape,
*second,
second_shape),
String);
}
Handle<String> Factory::NewStringSlice(Handle<String> str,
StringShape shape,
int begin,
int end) {
CALL_HEAP_FUNCTION(str->Slice(shape, begin, end), String);
}
......
......@@ -98,11 +98,16 @@ class Factory : public AllStatic {
// Create a new cons string object which consists of a pair of strings.
static Handle<String> NewConsString(Handle<String> first,
Handle<String> second);
StringShape first_shape,
Handle<String> second,
StringShape second_shape);
// 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);
static Handle<String> NewStringSlice(Handle<String> str,
StringShape shape,
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
......
......@@ -117,9 +117,10 @@ void TransformToFastProperties(Handle<JSObject> object,
void FlattenString(Handle<String> string) {
if (string->IsFlat()) return;
CALL_HEAP_FUNCTION_VOID(string->Flatten());
ASSERT(string->IsFlat());
StringShape shape(*string);
if (string->IsFlat(shape)) return;
CALL_HEAP_FUNCTION_VOID(string->Flatten(shape));
ASSERT(string->IsFlat(StringShape(*string)));
}
......@@ -216,7 +217,8 @@ Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
Handle<String> SubString(Handle<String> str, int start, int end) {
CALL_HEAP_FUNCTION(str->Slice(start, end), String);
StringShape shape(*str);
CALL_HEAP_FUNCTION(str->Slice(shape, start, end), String);
}
......
......@@ -777,13 +777,15 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
return ScavengeObjectSlow(p, object);
}
static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
// A ConString object with Heap::empty_string() as the right side
// A ConsString object with Heap::empty_string() as the right side
// is a candidate for being shortcut by the scavenger.
ASSERT(object->map() == map);
return (map->instance_type() < FIRST_NONSTRING_TYPE) &&
(String::cast(object)->map_representation_tag(map) == kConsStringTag) &&
(ConsString::cast(object)->second() == Heap::empty_string());
if (map->instance_type() >= FIRST_NONSTRING_TYPE) return false;
StringShape shape(map);
return (shape.representation_tag() == kConsStringTag) &&
(ConsString::cast(object)->unchecked_second() == Heap::empty_string());
}
......@@ -794,7 +796,7 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
// Optimization: Bypass flattened ConsString objects.
if (IsShortcutCandidate(object, first_word.ToMap())) {
object = HeapObject::cast(ConsString::cast(object)->first());
object = HeapObject::cast(ConsString::cast(object)->unchecked_first());
*p = object;
// After patching *p we have to repeat the checks that object is in the
// active semispace of the young generation and not already copied.
......@@ -1344,32 +1346,43 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) {
}
Object* Heap::AllocateConsString(String* first, String* second) {
int first_length = first->length();
int second_length = second->length();
Object* Heap::AllocateConsString(String* first,
StringShape first_shape,
String* second,
StringShape second_shape) {
int first_length = first->length(first_shape);
int second_length = second->length(second_shape);
int length = first_length + second_length;
bool is_ascii = first->is_ascii_representation()
&& second->is_ascii_representation();
bool is_ascii = first_shape.IsAsciiRepresentation()
&& second_shape.IsAsciiRepresentation();
// If the resulting string is small make a flat string.
if (length < String::kMinNonFlatLength) {
ASSERT(first->IsFlat());
ASSERT(second->IsFlat());
ASSERT(first->IsFlat(first_shape));
ASSERT(second->IsFlat(second_shape));
if (is_ascii) {
Object* result = AllocateRawAsciiString(length);
if (result->IsFailure()) return result;
// Copy the characters into the new object.
char* dest = SeqAsciiString::cast(result)->GetChars();
String::WriteToFlat(first, dest, 0, first_length);
String::WriteToFlat(second, dest + first_length, 0, second_length);
String::WriteToFlat(first, first_shape, dest, 0, first_length);
String::WriteToFlat(second,
second_shape,
dest + first_length,
0,
second_length);
return result;
} else {
Object* result = AllocateRawTwoByteString(length);
if (result->IsFailure()) return result;
// Copy the characters into the new object.
uc16* dest = SeqTwoByteString::cast(result)->GetChars();
String::WriteToFlat(first, dest, 0, first_length);
String::WriteToFlat(second, dest + first_length, 0, second_length);
String::WriteToFlat(first, first_shape, dest, 0, first_length);
String::WriteToFlat(second,
second_shape,
dest + first_length,
0,
second_length);
return result;
}
}
......@@ -1397,24 +1410,30 @@ Object* Heap::AllocateConsString(String* first, String* second) {
}
Object* Heap::AllocateSlicedString(String* buffer, int start, int end) {
Object* Heap::AllocateSlicedString(String* buffer,
StringShape buffer_shape,
int start,
int end) {
int length = end - start;
// If the resulting string is small make a sub string.
if (end - start <= String::kMinNonFlatLength) {
return Heap::AllocateSubString(buffer, start, end);
return Heap::AllocateSubString(buffer, buffer_shape, start, end);
}
Map* map;
if (length <= String::kMaxShortStringSize) {
map = buffer->is_ascii_representation() ? short_sliced_ascii_string_map()
: short_sliced_string_map();
map = buffer_shape.IsAsciiRepresentation() ?
short_sliced_ascii_string_map() :
short_sliced_string_map();
} else if (length <= String::kMaxMediumStringSize) {
map = buffer->is_ascii_representation() ? medium_sliced_ascii_string_map()
: medium_sliced_string_map();
map = buffer_shape.IsAsciiRepresentation() ?
medium_sliced_ascii_string_map() :
medium_sliced_string_map();
} else {
map = buffer->is_ascii_representation() ? long_sliced_ascii_string_map()
: long_sliced_string_map();
map = buffer_shape.IsAsciiRepresentation() ?
long_sliced_ascii_string_map() :
long_sliced_string_map();
}
Object* result = Allocate(map, NEW_SPACE);
......@@ -1429,34 +1448,42 @@ Object* Heap::AllocateSlicedString(String* buffer, int start, int end) {
}
Object* Heap::AllocateSubString(String* buffer, int start, int end) {
Object* Heap::AllocateSubString(String* buffer,
StringShape buffer_shape,
int start,
int end) {
int length = end - start;
if (length == 1) {
return Heap::LookupSingleCharacterStringFromCode(buffer->Get(start));
return Heap::LookupSingleCharacterStringFromCode(
buffer->Get(buffer_shape, start));
}
// Make an attempt to flatten the buffer to reduce access time.
buffer->TryFlatten();
if (!buffer->IsFlat(buffer_shape)) {
buffer->TryFlatten(buffer_shape);
buffer_shape = StringShape(buffer);
}
Object* result = buffer->is_ascii_representation()
Object* result = buffer_shape.IsAsciiRepresentation()
? AllocateRawAsciiString(length)
: AllocateRawTwoByteString(length);
if (result->IsFailure()) return result;
// Copy the characters into the new object.
String* string_result = String::cast(result);
StringShape result_shape(string_result);
StringHasher hasher(length);
int i = 0;
for (; i < length && hasher.is_array_index(); i++) {
uc32 c = buffer->Get(start + i);
uc32 c = buffer->Get(buffer_shape, start + i);
hasher.AddCharacter(c);
string_result->Set(i, c);
string_result->Set(result_shape, i, c);
}
for (; i < length; i++) {
uc32 c = buffer->Get(start + i);
uc32 c = buffer->Get(buffer_shape, start + i);
hasher.AddCharacterNoIndex(c);
string_result->Set(i, c);
string_result->Set(result_shape, i, c);
}
string_result->set_length_field(hasher.GetHashField());
return result;
......@@ -1525,8 +1552,9 @@ Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
Object* result = Heap::AllocateRawTwoByteString(1);
if (result->IsFailure()) return result;
String::cast(result)->Set(0, code);
return result;
String* answer = String::cast(result);
answer->Set(StringShape(answer), 0, code);
return answer;
}
......@@ -1905,9 +1933,10 @@ Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
// Convert and copy the characters into the new object.
String* string_result = String::cast(result);
decoder->Reset(string.start(), string.length());
StringShape result_shape(string_result);
for (int i = 0; i < chars; i++) {
uc32 r = decoder->GetNext();
string_result->Set(i, r);
string_result->Set(result_shape, i, r);
}
return result;
}
......@@ -1930,8 +1959,9 @@ Object* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
// Copy the characters into the new object, which may be either ASCII or
// UTF-16.
String* string_result = String::cast(result);
StringShape result_shape(string_result);
for (int i = 0; i < string.length(); i++) {
string_result->Set(i, string[i]);
string_result->Set(result_shape, i, string[i]);
}
return result;
}
......@@ -2043,15 +2073,17 @@ Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
reinterpret_cast<HeapObject*>(result)->set_map(map);
// The hash value contains the length of the string.
String::cast(result)->set_length_field(length_field);
String* answer = String::cast(result);
StringShape answer_shape(answer);
answer->set_length_field(length_field);
ASSERT_EQ(size, String::cast(result)->Size());
ASSERT_EQ(size, answer->Size());
// Fill in the characters.
for (int i = 0; i < chars; i++) {
String::cast(result)->Set(i, buffer->GetNext());
answer->Set(answer_shape, i, buffer->GetNext());
}
return result;
return answer;
}
......
......@@ -494,7 +494,10 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
static Object* AllocateConsString(String* first, String* second);
static Object* AllocateConsString(String* first,
StringShape first_shape,
String* second,
StringShape second_shape);
// Allocates a new sliced string object which is a slice of an underlying
// string buffer stretching from the index start (inclusive) to the index
......@@ -502,7 +505,10 @@ class Heap : public AllStatic {
// 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);
static Object* AllocateSlicedString(String* buffer,
StringShape buffer_shape,
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
......@@ -510,7 +516,10 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
static Object* AllocateSubString(String* buffer, int start, int end);
static Object* AllocateSubString(String* buffer,
StringShape buffer_shape,
int start,
int end);
// Allocate a new external string object, which is backed by a string
// resource that resides outside the V8 heap.
......
......@@ -129,34 +129,37 @@ Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
// Converts a source string to a 16 bit flat string or a SlicedString containing
// a 16 bit flat string).
Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
if (!pattern->IsFlat()) {
StringShape shape(*pattern);
if (!pattern->IsFlat(shape)) {
FlattenString(pattern);
}
Handle<String> flat_string(pattern->IsConsString() ?
Handle<String> flat_string(shape.IsCons() ?
String::cast(ConsString::cast(*pattern)->first()) :
*pattern);
ASSERT(!flat_string->IsConsString());
ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
flat_string->IsExternalString());
if (!flat_string->IsAsciiRepresentation()) {
ASSERT(flat_string->IsString());
StringShape flat_shape(*flat_string);
ASSERT(!flat_shape.IsCons());
ASSERT(flat_shape.IsSequential() ||
flat_shape.IsSliced() ||
flat_shape.IsExternal());
if (!flat_shape.IsAsciiRepresentation()) {
return flat_string;
}
int len = flat_string->length(flat_shape);
Handle<String> two_byte_string =
Factory::NewRawTwoByteString(flat_string->length(), TENURED);
static StringInputBuffer convert_to_two_byte_buffer;
convert_to_two_byte_buffer.Reset(*flat_string);
for (int i = 0; convert_to_two_byte_buffer.has_more(); i++) {
two_byte_string->Set(i, convert_to_two_byte_buffer.GetNext());
}
Factory::NewRawTwoByteString(len, TENURED);
uc16* dest = SeqTwoByteString::cast(*two_byte_string)->GetChars();
String::WriteToFlat(*flat_string, flat_shape, dest, 0, len);
return two_byte_string;
}
static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
int flags = JSRegExp::NONE;
for (int i = 0; i < str->length(); i++) {
switch (str->Get(i)) {
StringShape shape(*str);
for (int i = 0; i < str->length(shape); i++) {
switch (str->Get(shape, i)) {
case 'i':
flags |= JSRegExp::IGNORE_CASE;
break;
......@@ -182,13 +185,14 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
bool in_cache = !cached.is_null();
Handle<Object> result;
StringShape shape(*pattern);
if (in_cache) {
re->set_data(*cached);
result = re;
} else {
bool is_atom = !flags.is_ignore_case();
for (int i = 0; is_atom && i < pattern->length(); i++) {
if (is_reg_exp_special_char.get(pattern->Get(i)))
for (int i = 0; is_atom && i < pattern->length(shape); i++) {
if (is_reg_exp_special_char.get(pattern->Get(shape, i)))
is_atom = false;
}
if (is_atom) {
......
......@@ -350,11 +350,12 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path,
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::LogString(Handle<String> str) {
int len = str->length();
StringShape shape(*str);
int len = str->length(shape);
if (len > 256)
len = 256;
for (int i = 0; i < len; i++) {
uc32 c = str->Get(i);
uc32 c = str->Get(shape, i);
if (c < 32 || (c > 126 && c <= 255)) {
fprintf(logfile_, "\\x%02x", c);
} else if (c > 255) {
......@@ -430,7 +431,8 @@ void Logger::RegExpExecEvent(Handle<JSRegExp> regexp,
LogRegExpSource(regexp);
fprintf(logfile_, ",");
LogString(input_string);
fprintf(logfile_, ",%d..%d\n", start_index, input_string->length());
StringShape shape(*input_string);
fprintf(logfile_, ",%d..%d\n", start_index, input_string->length(shape));
#endif
}
......
......@@ -465,19 +465,20 @@ void JSValue::JSValueVerify() {
void String::StringPrint() {
if (IsSymbol()) {
StringShape shape(this);
if (shape.IsSymbol()) {
PrintF("#");
} else if (IsConsString()) {
} else if (shape.IsCons()) {
PrintF("c\"");
} else {
PrintF("\"");
}
for (int i = 0; i < length(); i++) {
PrintF("%c", Get(i));
PrintF("%c", Get(shape, i));
}
if (!IsSymbol()) PrintF("\"");
if (!shape.IsSymbol()) PrintF("\"");
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -595,20 +595,16 @@ class Object BASE_EMBEDDED {
inline bool IsHeapObject();
inline bool IsHeapNumber();
inline bool IsString();
inline bool IsSymbol();
inline bool IsSeqString();
inline bool IsAsciiStringRepresentation();
inline bool IsTwoByteStringRepresentation();
inline bool IsSeqAsciiString();
inline bool IsSeqTwoByteString();
inline bool IsConsString();
inline bool IsSlicedString();
inline bool IsExternalString();
inline bool IsExternalAsciiString();
inline bool IsConsString();
inline bool IsExternalTwoByteString();
inline bool IsShortString();
inline bool IsMediumString();
inline bool IsLongString();
inline bool IsSymbol();
inline bool IsExternalAsciiString();
inline bool IsSeqTwoByteString();
inline bool IsSeqAsciiString();
inline bool IsNumber();
inline bool IsByteArray();
inline bool IsFailure();
......@@ -3022,6 +3018,53 @@ class StringHasher {
};
// The characteristics of a string are stored in its map. Retrieving these
// few bits of information is moderately expensive, involving two memory
// loads where the second is dependent on the first. To improve efficiency
// the shape of the string is given its own class so that it can be retrieved
// once and used for several string operations. A StringShape is small enough
// to be passed by value and is immutable, but be aware that flattening a
// string can potentially alter its shape.
//
// Most of the methods designed to interrogate a string as to its exact nature
// have been made into methods on StringShape in order to encourage the use of
// StringShape. The String class has both a length() and a length(StringShape)
// operation. The former is simpler to type, but the latter is faster if you
// need the StringShape for some other operation immediately before or after.
class StringShape BASE_EMBEDDED {
public:
inline explicit StringShape(String* s);
inline explicit StringShape(Map* s);
inline explicit StringShape(InstanceType t);
inline bool IsAsciiRepresentation();
inline bool IsTwoByteRepresentation();
inline bool IsSequential();
inline bool IsExternal();
inline bool IsCons();
inline bool IsSliced();
inline bool IsExternalAscii();
inline bool IsExternalTwoByte();
inline bool IsSequentialAscii();
inline bool IsSequentialTwoByte();
inline bool IsSymbol();
inline StringRepresentationTag representation_tag();
inline uint32_t full_representation_tag();
inline uint32_t size_tag();
#ifdef DEBUG
inline uint32_t type() { return type_; }
inline void invalidate() { valid_ = false; }
inline bool valid() { return valid_; }
#else
inline void invalidate() { }
#endif
private:
uint32_t type_;
#ifdef DEBUG
bool valid_;
#endif
};
// The String abstract class captures JavaScript string values:
//
// Ecma-262:
......@@ -3033,6 +3076,9 @@ class StringHasher {
class String: public HeapObject {
public:
// Get and set the length of the string.
// Fast version.
inline int length(StringShape shape);
// Easy version.
inline int length();
inline void set_length(int value);
......@@ -3044,32 +3090,20 @@ class String: public HeapObject {
inline void set_length_field(uint32_t value);
// Get and set individual two byte chars in the string.
inline void Set(int index, uint16_t value);
inline void Set(StringShape shape, int index, uint16_t value);
// Get individual two byte char in the string. Repeated calls
// to this method are not efficient unless the string is flat.
inline uint16_t Get(int index);
inline uint16_t Get(StringShape shape, int index);
// 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.
Object* Flatten();
Object* Flatten(StringShape shape);
// Try to flatten the string. Do not allow handling of allocation
// failures. After calling TryFlatten, the string could still be a
// ConsString.
inline void TryFlatten();
// Is this string an ascii string.
inline bool IsAsciiRepresentation();
// Specialization of this function from Object that skips the
// string check.
inline bool IsSeqAsciiString();
// Fast testing routines that assume the receiver is a string and
// just check whether it is a certain kind of string.
inline bool StringIsSlicedString();
inline bool StringIsConsString();
inline void TryFlatten(StringShape shape);
Vector<const char> ToAsciiVector();
Vector<const uc16> ToUC16Vector();
......@@ -3079,7 +3113,7 @@ class String: public HeapObject {
bool MarkAsUndetectable();
// Slice the string and return a substring.
Object* Slice(int from, int to);
Object* Slice(StringShape shape, int from, int to);
// String equality operations.
inline bool Equals(String* other);
......@@ -3135,24 +3169,6 @@ class String: public HeapObject {
void PrintOn(FILE* out);
// Get the size tag.
inline uint32_t size_tag();
static inline uint32_t map_size_tag(Map* map);
// True if the string is a symbol.
inline bool is_symbol();
static inline bool is_symbol_map(Map* map);
// True if the string is ASCII.
inline bool is_ascii_representation();
static inline bool is_ascii_representation_map(Map* map);
// Get the representation tag.
inline StringRepresentationTag representation_tag();
// Get the representation and ASCII tag.
inline int full_representation_tag();
static inline StringRepresentationTag map_representation_tag(Map* map);
// For use during stack traces. Performs rudimentary sanity check.
bool LooksValid();
......@@ -3162,7 +3178,7 @@ class String: public HeapObject {
void StringPrint();
void StringVerify();
#endif
inline bool IsFlat();
inline bool IsFlat(StringShape shape);
// Layout description.
static const int kLengthOffset = HeapObject::kHeaderSize;
......@@ -3222,6 +3238,7 @@ class String: public HeapObject {
// Helper function for flattening strings.
template <typename sinkchar>
static void WriteToFlat(String* source,
StringShape shape,
sinkchar* sink,
int from,
int to);
......@@ -3262,7 +3279,9 @@ class String: public HeapObject {
private:
// Slow case of String::Equals. This implementation works on any strings
// but it is most efficient on strings that are almost flat.
bool SlowEquals(String* other);
bool SlowEquals(StringShape this_shape,
String* other,
StringShape other_shape);
// Slow case of AsArrayIndex.
bool SlowAsArrayIndex(uint32_t* index);
......@@ -3309,7 +3328,7 @@ class SeqAsciiString: public SeqString {
// Garbage collection support. This method is called by the
// garbage collector to compute the actual size of an AsciiString
// instance.
inline int SeqAsciiStringSize(Map* map);
inline int SeqAsciiStringSize(StringShape shape);
// Computes the size for an AsciiString instance of a given length.
static int SizeFor(int length) {
......@@ -3354,7 +3373,7 @@ class SeqTwoByteString: public SeqString {
// Garbage collection support. This method is called by the
// garbage collector to compute the actual size of a TwoByteString
// instance.
inline int SeqTwoByteStringSize(Map* map);
inline int SeqTwoByteStringSize(StringShape shape);
// Computes the size for a TwoByteString instance of a given length.
static int SizeFor(int length) {
......@@ -3384,14 +3403,20 @@ class SeqTwoByteString: public SeqString {
// values in a left-to-right depth-first traversal of the tree.
class ConsString: public String {
public:
// First object of the cons cell.
inline Object* first();
inline void set_first(Object* first,
// First string of the cons cell.
inline String* first();
// Doesn't check that the result is a string, even in debug mode. This is
// useful during GC where the mark bits confuse the checks.
inline Object* unchecked_first();
inline void set_first(String* first,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Second object of the cons cell.
inline Object* second();
inline void set_second(Object* second,
// Second string of the cons cell.
inline String* second();
// Doesn't check that the result is a string, even in debug mode. This is
// useful during GC where the mark bits confuse the checks.
inline Object* unchecked_second();
inline void set_second(String* second,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Dispatched behavior.
......@@ -3433,8 +3458,8 @@ class ConsString: public String {
class SlicedString: public String {
public:
// The underlying string buffer.
inline Object* buffer();
inline void set_buffer(Object* buffer);
inline String* buffer();
inline void set_buffer(String* buffer);
// The start index of the slice.
inline int start();
......
......@@ -737,10 +737,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
StatsRateScope timer(&Counters::parse);
Counters::total_parse_size.Increment(source->length());
StringShape shape(*source);
Counters::total_parse_size.Increment(source->length(shape));
// Initialize parser state.
source->TryFlatten();
source->TryFlatten(shape);
scanner_.Init(source, stream, 0);
ASSERT(target_stack_ == NULL);
......@@ -767,7 +768,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
temp_scope.materialized_literal_count(),
temp_scope.contains_array_literal(),
temp_scope.expected_property_count(),
0, 0, source->length(), false));
0, 0, source->length(shape), false));
} else if (scanner().stack_overflow()) {
Top::StackOverflow();
}
......@@ -789,11 +790,12 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
bool is_expression) {
ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
StatsRateScope timer(&Counters::parse_lazy);
Counters::total_parse_size.Increment(source->length());
StringShape shape(*source);
source->TryFlatten(shape);
Counters::total_parse_size.Increment(source->length(shape));
SafeStringInputBuffer buffer(source.location());
// Initialize parser state.
source->TryFlatten();
scanner_.Init(source, &buffer, start_position);
ASSERT(target_stack_ == NULL);
mode_ = PARSE_EAGERLY;
......
......@@ -503,9 +503,10 @@ void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
Object* object = *value;
if (object->IsString()) {
String* string = String::cast(object);
StringShape shape(string);
if (quote) Print("\"");
for (int i = 0; i < string->length(); i++) {
Print("%c", string->Get(i));
for (int i = 0; i < string->length(shape); i++) {
Print("%c", string->Get(shape, i));
}
if (quote) Print("\"");
} else if (object == Heap::null_value()) {
......
......@@ -45,7 +45,7 @@ class Descriptor BASE_EMBEDDED {
}
Object* KeyToSymbol() {
if (!key_->IsSymbol()) {
if (!StringShape(key_).IsSymbol()) {
Object* result = Heap::LookupSymbol(key_);
if (result->IsFailure()) return result;
key_ = String::cast(result);
......
This diff is collapsed.
......@@ -248,9 +248,10 @@ TEST(GarbageCollection) {
static void VerifyStringAllocation(const char* string) {
String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
CHECK_EQ(static_cast<int>(strlen(string)), s->length());
for (int index = 0; index < s->length(); index++) {
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); }
StringShape shape(s);
CHECK_EQ(static_cast<int>(strlen(string)), s->length(shape));
for (int index = 0; index < s->length(shape); index++) {
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(shape, index)); }
}
......
......@@ -62,7 +62,8 @@ static void InitializeBuildingBlocks(
building_blocks[i] =
Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
StringShape shape(*building_blocks[i]);
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
}
break;
}
......@@ -74,7 +75,8 @@ static void InitializeBuildingBlocks(
building_blocks[i] =
Factory::NewStringFromAscii(Vector<const char>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
StringShape shape(*building_blocks[i]);
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
}
break;
}
......@@ -99,7 +101,8 @@ static void InitializeBuildingBlocks(
Resource* resource = new Resource(Vector<const uc16>(buf, len));
building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
StringShape shape(*building_blocks[i]);
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
}
break;
}
......@@ -111,7 +114,8 @@ static void InitializeBuildingBlocks(
building_blocks[i] =
Factory::NewStringFromAscii(Vector<const char>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
StringShape shape(*building_blocks[i]);
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
}
break;
}
......@@ -125,9 +129,11 @@ static Handle<String> ConstructLeft(
int depth) {
Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
for (int i = 0; i < depth; i++) {
answer =
Factory::NewConsString(answer,
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
answer = Factory::NewConsString(
answer,
StringShape(*answer),
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]));
}
return answer;
}
......@@ -138,9 +144,11 @@ static Handle<String> ConstructRight(
int depth) {
Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
for (int i = depth - 1; i >= 0; i--) {
answer =
Factory::NewConsString(building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
answer);
answer = Factory::NewConsString(
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]),
answer,
StringShape(*answer));
}
return answer;
}
......@@ -157,11 +165,19 @@ static Handle<String> ConstructBalancedHelper(
if (to - from == 2) {
return Factory::NewConsString(
building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
StringShape(*building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]),
building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS],
StringShape(*building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]));
}
Handle<String> part1 =
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
Handle<String> part2 =
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
return Factory::NewConsString(
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
part1,
StringShape(*part1),
part2,
StringShape(*part2));
}
......@@ -199,8 +215,10 @@ static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
CHECK_EQ(c, buffer2.GetNext());
i++;
}
s1->Get(s1->length() - 1);
s2->Get(s2->length() - 1);
StringShape shape1(*s1);
StringShape shape2(*s2);
s1->Get(shape1, s1->length(shape1) - 1);
s2->Get(shape2, s2->length(shape2) - 1);
}
......@@ -233,10 +251,12 @@ TEST(Traverse) {
printf("7\n");
Handle<String> right_deep_slice =
Factory::NewStringSlice(left_deep_asymmetric,
StringShape(*left_deep_asymmetric),
left_deep_asymmetric->length() - 1050,
left_deep_asymmetric->length() - 50);
Handle<String> left_deep_slice =
Factory::NewStringSlice(right_deep_asymmetric,
StringShape(*right_deep_asymmetric),
right_deep_asymmetric->length() - 1050,
right_deep_asymmetric->length() - 50);
printf("8\n");
......@@ -262,7 +282,10 @@ TEST(Traverse) {
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);
return Factory::NewStringSlice(underlying,
StringShape(*underlying),
start,
end);
}
......@@ -280,11 +303,19 @@ static Handle<String> ConstructSliceTree(
Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
if (gen() % 2 == 0)
rhs = SliceOf(rhs);
return Factory::NewConsString(lhs, rhs);
return Factory::NewConsString(lhs,
StringShape(*lhs),
rhs,
StringShape(*rhs));
}
Handle<String> branch = Factory::NewConsString(
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
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,
StringShape(*part1),
part2,
StringShape(*part2));
if (gen() % 2 == 0)
return branch;
return(SliceOf(branch));
......@@ -324,9 +355,15 @@ TEST(DeepAscii) {
Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
string = Factory::NewConsString(string, foo_string);
string = Factory::NewConsString(string,
StringShape(*string),
foo_string,
StringShape(*foo_string));
}
Handle<String> flat_string = Factory::NewConsString(string, foo_string);
Handle<String> flat_string = Factory::NewConsString(string,
StringShape(*string),
foo_string,
StringShape(*foo_string));
FlattenString(flat_string);
for (int i = 0; i < 500; i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment