| Index: runtime/vm/symbols.cc
|
| diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
|
| index be081818ba689bfeff188d4dc054f38f1e4668c5..d8683fe7ab967f99998d6d50db5beeadb3725482 100644
|
| --- a/runtime/vm/symbols.cc
|
| +++ b/runtime/vm/symbols.cc
|
| @@ -397,27 +397,59 @@ RawString* Symbols::FromConcat(const String& str1, const String& str2) {
|
| // up symbol from pieces instead of concatenating them first into a big string.
|
| RawString* Symbols::FromConcatAll(
|
| const GrowableHandlePtrArray<const String>& strs) {
|
| - GrowableArray<const char*> cchars(strs.length());
|
| - GrowableArray<intptr_t> lengths(strs.length());
|
| + const intptr_t strs_length = strs.length();
|
| + GrowableArray<intptr_t> lengths(strs_length);
|
| +
|
| intptr_t len_sum = 0;
|
| - for (intptr_t i = 0; i < strs.length(); i++) {
|
| - const char* to_cstr = strs[i].ToCString();
|
| - intptr_t len = strlen(to_cstr);
|
| - cchars.Add(to_cstr);
|
| - lengths.Add(len);
|
| - len_sum += len;
|
| + bool is_one_byte_string = true;
|
| + for (intptr_t i = 0; i < strs_length; i++) {
|
| + const String& str = strs[i];
|
| + const intptr_t str_len = str.Length();
|
| + if ((String::kMaxElements - len_sum) < str_len) {
|
| + Exceptions::ThrowOOM();
|
| + UNREACHABLE();
|
| + }
|
| + len_sum += str_len;
|
| + lengths.Add(str_len);
|
| + if (!str.IsOneByteString()) {
|
| + is_one_byte_string = false;
|
| + }
|
| }
|
|
|
| Zone* zone = Thread::Current()->zone();
|
| - char* buffer = zone->Alloc<char>(len_sum);
|
| - const char* const orig_buffer = buffer;
|
| - for (intptr_t i = 0; i < cchars.length(); i++) {
|
| - intptr_t len = lengths[i];
|
| - strncpy(buffer, cchars[i], len);
|
| - buffer += len;
|
| - }
|
| - ASSERT(len_sum == buffer - orig_buffer);
|
| - return Symbols::New(orig_buffer, len_sum);
|
| +
|
| + if (is_one_byte_string) {
|
| + uint8_t* buffer = zone->Alloc<uint8_t>(len_sum);
|
| + const uint8_t* const orig_buffer = buffer;
|
| + for (intptr_t i = 0; i < strs_length; i++) {
|
| + NoSafepointScope no_safepoint;
|
| + intptr_t str_len = lengths[i];
|
| + const String& str = strs[i];
|
| + memmove(buffer, OneByteString::CharAddr(str, 0), str_len);
|
| + buffer += str_len;
|
| + }
|
| + ASSERT(len_sum == buffer - orig_buffer);
|
| + return Symbols::FromLatin1(orig_buffer, len_sum);
|
| + } else {
|
| + uint16_t* buffer = zone->Alloc<uint16_t>(len_sum);
|
| + const uint16_t* const orig_buffer = buffer;
|
| + for (intptr_t i = 0; i < strs_length; i++) {
|
| + NoSafepointScope no_safepoint;
|
| + intptr_t str_len = lengths[i];
|
| + const String& str = strs[i];
|
| + if (str.IsTwoByteString()) {
|
| + memmove(buffer, TwoByteString::CharAddr(str, 0), str_len * 2);
|
| + } else {
|
| + uint8_t* src_p = OneByteString::CharAddr(str, 0);
|
| + for (int n = 0; n < str_len; n++) {
|
| + buffer[n] = src_p[n];
|
| + }
|
| + }
|
| + buffer += str_len;
|
| + }
|
| + ASSERT(len_sum == buffer - orig_buffer);
|
| + return Symbols::FromUTF16(orig_buffer, len_sum);
|
| + }
|
| }
|
|
|
|
|
|
|