Commit 186d832c authored by antonm@chromium.org's avatar antonm@chromium.org

Introduce new runtime function to make join with lower memory usage.

Do not use generic StringBuilderConcat which requires array passed
to keep both elements and separator (which roughly double size
of the array).  That should be faster as well.

BUG=crbug.com/54580

Review URL: http://codereview.chromium.org/6520004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6777 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1e4800b9
......@@ -161,15 +161,7 @@ function Join(array, length, separator, convert) {
var result = %_FastAsciiArrayJoin(elements, separator);
if (!IS_UNDEFINED(result)) return result;
var length2 = (length << 1) - 1;
var j = length2;
var i = length;
elements[--j] = elements[--i];
while (i > 0) {
elements[--j] = separator;
elements[--j] = elements[--i];
}
return %StringBuilderConcat(elements, length2, '');
return %StringBuilderJoin(elements, length, separator);
} finally {
// Make sure to remove the last element of the visited array no
// matter what happens.
......
......@@ -5803,6 +5803,84 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
}
static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, array, args[0]);
if (!args[1]->IsSmi()) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
int array_length = Smi::cast(args[1])->value();
CONVERT_CHECKED(String, separator, args[2]);
if (!array->HasFastElements()) {
return Top::Throw(Heap::illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
array_length = fixed_array->length();
}
if (array_length == 0) {
return Heap::empty_string();
} else if (array_length == 1) {
Object* first = fixed_array->get(0);
if (first->IsString()) return first;
}
int separator_length = separator->length();
int max_nof_separators =
(String::kMaxLength + separator_length - 1) / separator_length;
if (max_nof_separators < (array_length - 1)) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
int length = (array_length - 1) * separator_length;
for (int i = 0; i < array_length; i++) {
String* element = String::cast(fixed_array->get(i));
int increment = element->length();
if (increment > String::kMaxLength - length) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
length += increment;
}
Object* object;
{ MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
SeqTwoByteString* answer = SeqTwoByteString::cast(object);
uc16* sink = answer->GetChars();
#ifdef DEBUG
uc16* end = sink + length;
#endif
String* first = String::cast(fixed_array->get(0));
int first_length = first->length();
String::WriteToFlat(first, sink, 0, first_length);
sink += first_length;
for (int i = 1; i < array_length; i++) {
ASSERT(sink + separator_length <= end);
String::WriteToFlat(separator, sink, 0, separator_length);
sink += separator_length;
String* element = String::cast(fixed_array->get(i));
int element_length = element->length();
ASSERT(sink + element_length <= end);
String::WriteToFlat(element, sink, 0, element_length);
sink += element_length;
}
ASSERT(sink == end);
ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
return answer;
}
static MaybeObject* Runtime_NumberOr(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
......
......@@ -128,6 +128,7 @@ namespace internal {
\
F(StringAdd, 2, 1) \
F(StringBuilderConcat, 3, 1) \
F(StringBuilderJoin, 3, 1) \
\
/* Bit operations */ \
F(NumberOr, 2, 1) \
......
......@@ -118,8 +118,9 @@ var knownProblems = {
"Abort": true,
// Avoid calling the concat operation, because weird lengths
// may lead to out-of-memory.
// may lead to out-of-memory. Ditto for StringBuilderJoin.
"StringBuilderConcat": true,
"StringBuilderJoin": true,
// These functions use pseudo-stack-pointers and are not robust
// to unexpected integer values.
......
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