Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 654) |
+++ src/runtime.cc (working copy) |
@@ -952,9 +952,12 @@ |
// Flatten the string. If someone wants to get a char at an index |
// in a cons string, it is likely that more indices will be |
// accessed. |
- subject->TryFlatten(); |
- if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value(); |
- return Smi::FromInt(subject->Get(i)); |
+ StringShape shape(subject); |
+ subject->TryFlatten(shape); // shape no longer valid! |
+ if (i >= static_cast<uint32_t>(subject->length(StringShape(subject)))) { |
+ return Heap::nan_value(); |
+ } |
+ return Smi::FromInt(subject->Get(StringShape(subject), i)); |
} |
@@ -1334,39 +1337,47 @@ |
Handle<String> pat, |
int start_index) { |
ASSERT(0 <= start_index); |
- ASSERT(start_index <= sub->length()); |
+ StringShape sub_shape(*sub); |
+ StringShape pat_shape(*pat); |
+ ASSERT(start_index <= sub->length(sub_shape)); |
- int pattern_length = pat->length(); |
+ int pattern_length = pat->length(pat_shape); |
if (pattern_length == 0) return start_index; |
- int subject_length = sub->length(); |
+ int subject_length = sub->length(sub_shape); |
if (start_index + pattern_length > subject_length) return -1; |
- FlattenString(sub); |
+ if (!sub->IsFlat(sub_shape)) { |
+ FlattenString(sub); |
+ sub_shape = StringShape(*sub); |
+ } |
// Searching for one specific character is common. For one |
// character patterns linear search is necessary, so any smart |
// algorithm is unnecessary overhead. |
if (pattern_length == 1) { |
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
- if (sub->is_ascii_representation()) { |
- return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index); |
+ if (sub_shape.IsAsciiRepresentation()) { |
+ return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(pat_shape, 0), start_index); |
} |
- return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); |
+ return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(pat_shape, 0), start_index); |
} |
- FlattenString(pat); |
+ if (!pat->IsFlat(pat_shape)) { |
+ FlattenString(pat); |
+ pat_shape = StringShape(*pat); |
+ } |
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
// dispatch on type of strings |
- if (pat->is_ascii_representation()) { |
+ if (pat_shape.IsAsciiRepresentation()) { |
Vector<const char> pat_vector = pat->ToAsciiVector(); |
- if (sub->is_ascii_representation()) { |
+ if (sub_shape.IsAsciiRepresentation()) { |
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
} |
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
} |
Vector<const uc16> pat_vector = pat->ToUC16Vector(); |
- if (sub->is_ascii_representation()) { |
+ if (sub_shape.IsAsciiRepresentation()) { |
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
} |
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
@@ -1397,14 +1408,17 @@ |
CONVERT_CHECKED(String, pat, args[1]); |
Object* index = args[2]; |
- sub->TryFlatten(); |
- pat->TryFlatten(); |
+ sub->TryFlatten(StringShape(sub)); |
+ pat->TryFlatten(StringShape(pat)); |
+ StringShape sub_shape(sub); |
+ StringShape pat_shape(pat); |
+ |
uint32_t start_index; |
if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); |
- uint32_t pattern_length = pat->length(); |
- uint32_t sub_length = sub->length(); |
+ uint32_t pattern_length = pat->length(pat_shape); |
+ uint32_t sub_length = sub->length(sub_shape); |
if (start_index + pattern_length > sub_length) { |
start_index = sub_length - pattern_length; |
@@ -1413,7 +1427,7 @@ |
for (int i = start_index; i >= 0; i--) { |
bool found = true; |
for (uint32_t j = 0; j < pattern_length; j++) { |
- if (sub->Get(i + j) != pat->Get(j)) { |
+ if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) { |
found = false; |
break; |
} |
@@ -1433,8 +1447,10 @@ |
CONVERT_CHECKED(String, str2, args[1]); |
if (str1 == str2) return Smi::FromInt(0); // Equal. |
- int str1_length = str1->length(); |
- int str2_length = str2->length(); |
+ StringShape shape1(str1); |
+ StringShape shape2(str2); |
+ int str1_length = str1->length(shape1); |
+ int str2_length = str2->length(shape2); |
// Decide trivial cases without flattening. |
if (str1_length == 0) { |
@@ -1449,11 +1465,11 @@ |
// No need to flatten if we are going to find the answer on the first |
// character. At this point we know there is at least one character |
// in each string, due to the trivial case handling above. |
- int d = str1->Get(0) - str2->Get(0); |
+ int d = str1->Get(shape1, 0) - str2->Get(shape2, 0); |
if (d != 0) return Smi::FromInt(d); |
- str1->TryFlatten(); |
- str2->TryFlatten(); |
+ str1->TryFlatten(shape1); // Shapes are no longer valid now! |
+ str2->TryFlatten(shape2); |
static StringInputBuffer buf1; |
static StringInputBuffer buf2; |
@@ -1482,10 +1498,12 @@ |
int start = FastD2I(from_number); |
int end = FastD2I(to_number); |
+ StringShape shape(value); |
+ |
RUNTIME_ASSERT(end >= start); |
RUNTIME_ASSERT(start >= 0); |
- RUNTIME_ASSERT(end <= value->length()); |
- return value->Slice(start, end); |
+ RUNTIME_ASSERT(end <= value->length(shape)); |
+ return value->Slice(shape, start, end); |
} |
@@ -1588,9 +1606,11 @@ |
// Returns a single character string where first character equals |
// string->Get(index). |
static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
- if (index < static_cast<uint32_t>(string->length())) { |
- string->TryFlatten(); |
- return LookupSingleCharacterStringFromCode(string->Get(index)); |
+ StringShape shape(*string); |
+ if (index < static_cast<uint32_t>(string->length(shape))) { |
+ string->TryFlatten(shape); // Invalidates shape! |
+ return LookupSingleCharacterStringFromCode( |
+ string->Get(StringShape(*string), index)); |
} |
return Execution::CharAt(string, index); |
} |
@@ -1775,7 +1795,7 @@ |
result = SetElement(js_object, index, value); |
} else { |
Handle<String> key_string = Handle<String>::cast(key); |
- key_string->TryFlatten(); |
+ key_string->TryFlatten(StringShape(*key_string)); |
result = SetProperty(js_object, key_string, value, attr); |
} |
if (result.is_null()) return Failure::Exception(); |
@@ -1866,7 +1886,8 @@ |
uint32_t index; |
if (key->AsArrayIndex(&index)) { |
String* string = String::cast(args[0]); |
- if (index < static_cast<uint32_t>(string->length())) |
+ StringShape shape(string); |
+ if (index < static_cast<uint32_t>(string->length(shape))) |
return Heap::true_value(); |
} |
} |
@@ -2049,7 +2070,7 @@ |
NoHandleAllocation ha; |
ASSERT(args.length() == 1); |
CONVERT_CHECKED(String, subject, args[0]); |
- subject->TryFlatten(); |
+ subject->TryFlatten(StringShape(subject)); |
return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); |
} |
@@ -2079,10 +2100,11 @@ |
if (object->IsFailure()) return object; |
String* result = String::cast(object); |
+ StringShape result_shape(result); |
for (int i = 0; i < length; i++) { |
Object* element = codes->GetElement(i); |
CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
- result->Set(i, chr & 0xffff); |
+ result->Set(result_shape, i, chr & 0xffff); |
} |
return result; |
} |
@@ -2131,10 +2153,11 @@ |
ASSERT(args.length() == 1); |
CONVERT_CHECKED(String, source, args[0]); |
- source->TryFlatten(); |
+ source->TryFlatten(StringShape(source)); |
+ StringShape sshape(source); |
Mads Ager (chromium)
2008/11/03 08:45:49
How about source_shape?
|
int escaped_length = 0; |
- int length = source->length(); |
+ int length = source->length(sshape); |
{ |
Access<StringInputBuffer> buffer(&string_input_buffer); |
buffer->Reset(source); |
@@ -2161,27 +2184,28 @@ |
Object* o = Heap::AllocateRawAsciiString(escaped_length); |
if (o->IsFailure()) return o; |
String* destination = String::cast(o); |
+ StringShape dshape(destination); |
Mads Ager (chromium)
2008/11/03 08:45:49
dest_shape or even destination_shape?
Erik Corry
2008/11/03 09:33:54
I changed the other one, but I left this in, becau
|
int dest_position = 0; |
Access<StringInputBuffer> buffer(&string_input_buffer); |
buffer->Rewind(); |
while (buffer->has_more()) { |
- uint16_t character = buffer->GetNext(); |
- if (character >= 256) { |
- destination->Set(dest_position, '%'); |
- destination->Set(dest_position+1, 'u'); |
- destination->Set(dest_position+2, hex_chars[character >> 12]); |
- destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]); |
- destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]); |
- destination->Set(dest_position+5, hex_chars[character & 0xf]); |
+ uint16_t chr = buffer->GetNext(); |
+ if (chr >= 256) { |
+ destination->Set(dshape, dest_position, '%'); |
+ destination->Set(dshape, dest_position+1, 'u'); |
+ destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]); |
+ destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
+ destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
+ destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]); |
dest_position += 6; |
- } else if (IsNotEscaped(character)) { |
- destination->Set(dest_position, character); |
+ } else if (IsNotEscaped(chr)) { |
+ destination->Set(dshape, dest_position, chr); |
dest_position++; |
} else { |
- destination->Set(dest_position, '%'); |
- destination->Set(dest_position+1, hex_chars[character >> 4]); |
- destination->Set(dest_position+2, hex_chars[character & 0xf]); |
+ destination->Set(dshape, dest_position, '%'); |
+ destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]); |
+ destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]); |
dest_position += 3; |
} |
} |
@@ -2209,19 +2233,26 @@ |
} |
-static inline int Unescape(String* source, int i, int length, int* step) { |
- uint16_t character = source->Get(i); |
+static inline int Unescape(String* source, |
+ StringShape shape, |
+ int i, |
+ int length, |
+ int* step) { |
+ uint16_t character = source->Get(shape, i); |
int32_t hi, lo; |
if (character == '%' && |
i <= length - 6 && |
- source->Get(i + 1) == 'u' && |
- (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 && |
- (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) { |
+ source->Get(shape, i + 1) == 'u' && |
+ (hi = TwoDigitHex(source->Get(shape, i + 2), |
+ source->Get(shape, i + 3))) != -1 && |
+ (lo = TwoDigitHex(source->Get(shape, i + 4), |
+ source->Get(shape, i + 5))) != -1) { |
*step = 6; |
return (hi << 8) + lo; |
} else if (character == '%' && |
i <= length - 3 && |
- (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) { |
+ (lo = TwoDigitHex(source->Get(shape, i + 1), |
+ source->Get(shape, i + 2))) != -1) { |
*step = 3; |
return lo; |
} else { |
@@ -2236,15 +2267,16 @@ |
ASSERT(args.length() == 1); |
CONVERT_CHECKED(String, source, args[0]); |
- source->TryFlatten(); |
+ source->TryFlatten(StringShape(source)); |
+ StringShape sshape(source); |
Mads Ager (chromium)
2008/11/03 08:45:49
source_shape?
|
bool ascii = true; |
- int length = source->length(); |
+ int length = source->length(sshape); |
int unescaped_length = 0; |
for (int i = 0; i < length; unescaped_length++) { |
int step; |
- if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) |
+ if (Unescape(source, sshape, i, length, &step) > String::kMaxAsciiCharCode) |
ascii = false; |
i += step; |
} |
@@ -2258,11 +2290,14 @@ |
Heap::AllocateRawTwoByteString(unescaped_length); |
if (o->IsFailure()) return o; |
String* destination = String::cast(o); |
+ StringShape dshape(destination); |
Mads Ager (chromium)
2008/11/03 08:45:49
destination_shape?
|
int dest_position = 0; |
for (int i = 0; i < length; dest_position++) { |
int step; |
- destination->Set(dest_position, Unescape(source, i, length, &step)); |
+ destination->Set(dshape, |
+ dest_position, |
+ Unescape(source, sshape, i, length, &step)); |
i += step; |
} |
return destination; |
@@ -2276,31 +2311,33 @@ |
CONVERT_DOUBLE_CHECKED(n, args[1]); |
int radix = FastD2I(n); |
- s->TryFlatten(); |
+ s->TryFlatten(StringShape(s)); |
- int len = s->length(); |
+ StringShape shape(s); |
+ |
+ int len = s->length(shape); |
int i; |
// Skip leading white space. |
- for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; |
+ for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ; |
if (i == len) return Heap::nan_value(); |
// Compute the sign (default to +). |
int sign = 1; |
- if (s->Get(i) == '-') { |
+ if (s->Get(shape, i) == '-') { |
sign = -1; |
i++; |
- } else if (s->Get(i) == '+') { |
+ } else if (s->Get(shape, i) == '+') { |
i++; |
} |
// Compute the radix if 0. |
if (radix == 0) { |
radix = 10; |
- if (i < len && s->Get(i) == '0') { |
+ if (i < len && s->Get(shape, i) == '0') { |
radix = 8; |
if (i + 1 < len) { |
- int c = s->Get(i + 1); |
+ int c = s->Get(shape, i + 1); |
if (c == 'x' || c == 'X') { |
radix = 16; |
i += 2; |
@@ -2309,8 +2346,8 @@ |
} |
} else if (radix == 16) { |
// Allow 0x or 0X prefix if radix is 16. |
- if (i + 1 < len && s->Get(i) == '0') { |
- int c = s->Get(i + 1); |
+ if (i + 1 < len && s->Get(shape, i) == '0') { |
+ int c = s->Get(shape, i + 1); |
if (c == 'x' || c == 'X') i += 2; |
} |
} |
@@ -2347,12 +2384,14 @@ |
NoHandleAllocation ha; |
CONVERT_CHECKED(String, s, args[0]); |
- int raw_string_length = s->length(); |
+ s->TryFlatten(StringShape(s)); |
+ StringShape shape(s); |
+ |
+ int raw_string_length = s->length(shape); |
// Assume that the string is not empty; we need this assumption later |
if (raw_string_length == 0) return s; |
int length = raw_string_length; |
- s->TryFlatten(); |
// We try this twice, once with the assumption that the result is |
// no longer than the input and, if that assumption breaks, again |
@@ -2368,11 +2407,12 @@ |
// character is also ascii. This is currently the case, but it |
// might break in the future if we implement more context and locale |
// dependent upper/lower conversions. |
- Object* o = s->IsAsciiRepresentation() |
+ Object* o = shape.IsAsciiRepresentation() |
? Heap::AllocateRawAsciiString(length) |
: Heap::AllocateRawTwoByteString(length); |
if (o->IsFailure()) return o; |
String* result = String::cast(o); |
+ StringShape result_shape(result); |
bool has_changed_character = false; |
// Convert all characters to upper case, assuming that they will fit |
@@ -2389,12 +2429,12 @@ |
int char_length = mapping->get(current, next, chars); |
if (char_length == 0) { |
// The case conversion of this character is the character itself. |
- result->Set(i, current); |
+ result->Set(result_shape, i, current); |
i++; |
} else if (char_length == 1) { |
// Common case: converting the letter resulted in one character. |
ASSERT(static_cast<uc32>(chars[0]) != current); |
- result->Set(i, chars[0]); |
+ result->Set(result_shape, i, chars[0]); |
has_changed_character = true; |
i++; |
} else if (length == raw_string_length) { |
@@ -2429,7 +2469,7 @@ |
goto try_convert; |
} else { |
for (int j = 0; j < char_length; j++) { |
- result->Set(i, chars[j]); |
+ result->Set(result_shape, i, chars[j]); |
i++; |
} |
has_changed_character = true; |
@@ -2613,8 +2653,10 @@ |
CONVERT_CHECKED(String, str1, args[0]); |
CONVERT_CHECKED(String, str2, args[1]); |
- int len1 = str1->length(); |
- int len2 = str2->length(); |
+ StringShape shape1(str1); |
+ StringShape shape2(str2); |
+ int len1 = str1->length(shape1); |
+ int len2 = str2->length(shape2); |
if (len1 == 0) return str2; |
if (len2 == 0) return str1; |
int length_sum = len1 + len2; |
@@ -2624,12 +2666,13 @@ |
Top::context()->mark_out_of_memory(); |
return Failure::OutOfMemoryException(); |
} |
- return Heap::AllocateConsString(str1, str2); |
+ return Heap::AllocateConsString(str1, shape1, str2, shape2); |
} |
template<typename sinkchar> |
static inline void StringBuilderConcatHelper(String* special, |
+ StringShape special_shape, |
sinkchar* sink, |
FixedArray* fixed_array, |
int array_length) { |
@@ -2640,12 +2683,17 @@ |
int len = Smi::cast(element)->value(); |
int pos = len >> 11; |
len &= 0x7ff; |
- String::WriteToFlat(special, sink + position, pos, pos + len); |
+ String::WriteToFlat(special, |
+ special_shape, |
+ sink + position, |
+ pos, |
+ pos + len); |
position += len; |
} else { |
String* string = String::cast(element); |
- int element_length = string->length(); |
- String::WriteToFlat(string, sink + position, 0, element_length); |
+ StringShape shape(string); |
+ int element_length = string->length(shape); |
+ String::WriteToFlat(string, shape, sink + position, 0, element_length); |
position += element_length; |
} |
} |
@@ -2657,7 +2705,8 @@ |
ASSERT(args.length() == 2); |
CONVERT_CHECKED(JSArray, array, args[0]); |
CONVERT_CHECKED(String, special, args[1]); |
- int special_length = special->length(); |
+ StringShape special_shape(special); |
+ int special_length = special->length(special_shape); |
Object* smi_array_length = array->length(); |
if (!smi_array_length->IsSmi()) { |
Top::context()->mark_out_of_memory(); |
@@ -2679,7 +2728,7 @@ |
if (first->IsString()) return first; |
} |
- bool ascii = special->IsAsciiRepresentation(); |
+ bool ascii = special_shape.IsAsciiRepresentation(); |
int position = 0; |
for (int i = 0; i < array_length; i++) { |
Object* elt = fixed_array->get(i); |
@@ -2693,13 +2742,14 @@ |
position += len; |
} else if (elt->IsString()) { |
String* element = String::cast(elt); |
- int element_length = element->length(); |
+ StringShape element_shape(element); |
+ int element_length = element->length(element_shape); |
if (!Smi::IsValid(element_length + position)) { |
Top::context()->mark_out_of_memory(); |
return Failure::OutOfMemoryException(); |
} |
position += element_length; |
- if (ascii && !element->IsAsciiRepresentation()) { |
+ if (ascii && !element_shape.IsAsciiRepresentation()) { |
ascii = false; |
} |
} else { |
@@ -2715,6 +2765,7 @@ |
if (object->IsFailure()) return object; |
SeqAsciiString* answer = SeqAsciiString::cast(object); |
StringBuilderConcatHelper(special, |
+ special_shape, |
answer->GetChars(), |
fixed_array, |
array_length); |
@@ -2724,6 +2775,7 @@ |
if (object->IsFailure()) return object; |
SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
StringBuilderConcatHelper(special, |
+ special_shape, |
answer->GetChars(), |
fixed_array, |
array_length); |
@@ -2918,21 +2970,24 @@ |
CONVERT_CHECKED(String, x, args[0]); |
CONVERT_CHECKED(String, y, args[1]); |
+ StringShape x_shape(x); |
+ StringShape y_shape(y); |
+ |
// A few fast case tests before we flatten. |
if (x == y) return Smi::FromInt(EQUAL); |
- if (y->length() == 0) { |
- if (x->length() == 0) return Smi::FromInt(EQUAL); |
+ if (y->length(y_shape) == 0) { |
+ if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL); |
return Smi::FromInt(GREATER); |
- } else if (x->length() == 0) { |
+ } else if (x->length(x_shape) == 0) { |
return Smi::FromInt(LESS); |
} |
- int d = x->Get(0) - y->Get(0); |
+ int d = x->Get(x_shape, 0) - y->Get(y_shape, 0); |
if (d < 0) return Smi::FromInt(LESS); |
else if (d > 0) return Smi::FromInt(GREATER); |
- x->TryFlatten(); |
- y->TryFlatten(); |
+ x->TryFlatten(x_shape); // Shapes are no longer valid! |
+ y->TryFlatten(y_shape); |
static StringInputBuffer bufx; |
static StringInputBuffer bufy; |