Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 3191) |
+++ src/runtime.cc (working copy) |
@@ -1357,8 +1357,9 @@ |
StringBuilderSubstringPosition::encode(from); |
AddElement(Smi::FromInt(encoded_slice)); |
} else { |
- Handle<String> slice = Factory::NewStringSlice(subject_, from, to); |
- AddElement(*slice); |
+ // Otherwise encode as two smis. |
+ AddElement(Smi::FromInt(-length)); |
+ AddElement(Smi::FromInt(from)); |
} |
IncrementCharacterCount(length); |
} |
@@ -1750,8 +1751,9 @@ |
int prev = 0; |
// Number of parts added by compiled replacement plus preceeding string |
- // and possibly suffix after last match. |
- const int parts_added_per_loop = compiled_replacement.parts() + 2; |
+ // and possibly suffix after last match. It is possible for compiled |
+ // replacements to use two elements when encoded as two smis. |
+ const int parts_added_per_loop = compiled_replacement.parts() * 2 + 2; |
bool matched = true; |
do { |
ASSERT(last_match_info_handle->HasFastElements()); |
@@ -3766,9 +3768,21 @@ |
for (int i = 0; i < array_length; i++) { |
Object* element = fixed_array->get(i); |
if (element->IsSmi()) { |
+ // Smi encoding of position and length. |
int encoded_slice = Smi::cast(element)->value(); |
- int pos = StringBuilderSubstringPosition::decode(encoded_slice); |
- int len = StringBuilderSubstringLength::decode(encoded_slice); |
+ int pos; |
+ int len; |
+ if (encoded_slice > 0) { |
+ // Position and length encoded in one smi. |
+ pos = StringBuilderSubstringPosition::decode(encoded_slice); |
+ len = StringBuilderSubstringLength::decode(encoded_slice); |
+ } else { |
+ // Position and length encoded in two smis. |
+ Object* obj = fixed_array->get(++i); |
+ ASSERT(obj->IsSmi()); |
+ pos = Smi::cast(obj)->value(); |
+ len = -encoded_slice; |
+ } |
String::WriteToFlat(special, |
sink + position, |
pos, |
@@ -3789,6 +3803,10 @@ |
ASSERT(args.length() == 2); |
CONVERT_CHECKED(JSArray, array, args[0]); |
CONVERT_CHECKED(String, special, args[1]); |
+ |
+ // This assumption is used by the slice encoding in one or two smis. |
+ ASSERT(Smi::kMaxValue >= String::kMaxLength); |
+ |
int special_length = special->length(); |
Object* smi_array_length = array->length(); |
if (!smi_array_length->IsSmi()) { |
@@ -3816,13 +3834,29 @@ |
for (int i = 0; i < array_length; i++) { |
Object* elt = fixed_array->get(i); |
if (elt->IsSmi()) { |
+ // Smi encoding of position and length. |
int len = Smi::cast(elt)->value(); |
- int pos = len >> 11; |
- len &= 0x7ff; |
- if (pos + len > special_length) { |
- return Top::Throw(Heap::illegal_argument_symbol()); |
+ if (len > 0) { |
+ // Position and length encoded in one smi. |
+ int pos = len >> 11; |
+ len &= 0x7ff; |
+ if (pos + len > special_length) { |
+ return Top::Throw(Heap::illegal_argument_symbol()); |
+ } |
+ position += len; |
+ } else { |
+ // Position and length encoded in two smis. |
+ position += (-len); |
+ // Get the position and check that it is also a smi. |
+ i++; |
+ if (i >= array_length) { |
+ return Top::Throw(Heap::illegal_argument_symbol()); |
+ } |
+ Object* pos = fixed_array->get(i); |
+ if (!pos->IsSmi()) { |
+ return Top::Throw(Heap::illegal_argument_symbol()); |
+ } |
} |
- position += len; |
} else if (elt->IsString()) { |
String* element = String::cast(elt); |
int element_length = element->length(); |