| Index: src/runtime/runtime-strings.cc
|
| diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc
|
| index b109ae07b29e94d0a6efdfb97a6361405b40e287..03b8a08afa09bea3a5936e67eb9ca1fed08abc4f 100644
|
| --- a/src/runtime/runtime-strings.cc
|
| +++ b/src/runtime/runtime-strings.cc
|
| @@ -496,6 +496,89 @@
|
| }
|
| }
|
|
|
| +
|
| +RUNTIME_FUNCTION(Runtime_StringBuilderJoin) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 3);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
|
| + int32_t array_length;
|
| + if (!args[1]->ToInt32(&array_length)) {
|
| + THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
|
| + }
|
| + CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
|
| + RUNTIME_ASSERT(array->HasFastObjectElements());
|
| + RUNTIME_ASSERT(array_length >= 0);
|
| +
|
| + Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
|
| + if (fixed_array->length() < array_length) {
|
| + array_length = fixed_array->length();
|
| + }
|
| +
|
| + if (array_length == 0) {
|
| + return isolate->heap()->empty_string();
|
| + } else if (array_length == 1) {
|
| + Object* first = fixed_array->get(0);
|
| + RUNTIME_ASSERT(first->IsString());
|
| + return first;
|
| + }
|
| +
|
| + int separator_length = separator->length();
|
| + RUNTIME_ASSERT(separator_length > 0);
|
| + int max_nof_separators =
|
| + (String::kMaxLength + separator_length - 1) / separator_length;
|
| + if (max_nof_separators < (array_length - 1)) {
|
| + THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
|
| + }
|
| + int length = (array_length - 1) * separator_length;
|
| + for (int i = 0; i < array_length; i++) {
|
| + Object* element_obj = fixed_array->get(i);
|
| + RUNTIME_ASSERT(element_obj->IsString());
|
| + String* element = String::cast(element_obj);
|
| + int increment = element->length();
|
| + if (increment > String::kMaxLength - length) {
|
| + STATIC_ASSERT(String::kMaxLength < kMaxInt);
|
| + length = kMaxInt; // Provoke exception;
|
| + break;
|
| + }
|
| + length += increment;
|
| + }
|
| +
|
| + Handle<SeqTwoByteString> answer;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, answer, isolate->factory()->NewRawTwoByteString(length));
|
| +
|
| + DisallowHeapAllocation no_gc;
|
| +
|
| + uc16* sink = answer->GetChars();
|
| +#ifdef DEBUG
|
| + uc16* end = sink + length;
|
| +#endif
|
| +
|
| + RUNTIME_ASSERT(fixed_array->get(0)->IsString());
|
| + String* first = String::cast(fixed_array->get(0));
|
| + String* separator_raw = *separator;
|
| + int first_length = first->length();
|
| + String::WriteToFlat(first, sink, 0, first_length);
|
| + sink += first_length;
|
| +
|
| + for (int i = 1; i < array_length; i++) {
|
| + DCHECK(sink + separator_length <= end);
|
| + String::WriteToFlat(separator_raw, sink, 0, separator_length);
|
| + sink += separator_length;
|
| +
|
| + RUNTIME_ASSERT(fixed_array->get(i)->IsString());
|
| + String* element = String::cast(fixed_array->get(i));
|
| + int element_length = element->length();
|
| + DCHECK(sink + element_length <= end);
|
| + String::WriteToFlat(element, sink, 0, element_length);
|
| + sink += element_length;
|
| + }
|
| + DCHECK(sink == end);
|
| +
|
| + // Use %_FastOneByteArrayJoin instead.
|
| + DCHECK(!answer->IsOneByteRepresentation());
|
| + return *answer;
|
| +}
|
|
|
| template <typename Char>
|
| static void JoinSparseArrayWithSeparator(FixedArray* elements,
|
|
|