Chromium Code Reviews| 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; |