OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3323 | 3323 |
3324 class ReplacementStringBuilder { | 3324 class ReplacementStringBuilder { |
3325 public: | 3325 public: |
3326 ReplacementStringBuilder(Heap* heap, | 3326 ReplacementStringBuilder(Heap* heap, |
3327 Handle<String> subject, | 3327 Handle<String> subject, |
3328 int estimated_part_count) | 3328 int estimated_part_count) |
3329 : heap_(heap), | 3329 : heap_(heap), |
3330 array_builder_(heap->isolate(), estimated_part_count), | 3330 array_builder_(heap->isolate(), estimated_part_count), |
3331 subject_(subject), | 3331 subject_(subject), |
3332 character_count_(0), | 3332 character_count_(0), |
3333 is_ascii_(subject->IsOneByteRepresentation()) { | 3333 is_ascii_(subject->IsOneByteRepresentation()), |
| 3334 overflowed_(false) { |
3334 // Require a non-zero initial size. Ensures that doubling the size to | 3335 // Require a non-zero initial size. Ensures that doubling the size to |
3335 // extend the array will work. | 3336 // extend the array will work. |
3336 ASSERT(estimated_part_count > 0); | 3337 ASSERT(estimated_part_count > 0); |
3337 } | 3338 } |
3338 | 3339 |
3339 static inline void AddSubjectSlice(FixedArrayBuilder* builder, | 3340 static inline void AddSubjectSlice(FixedArrayBuilder* builder, |
3340 int from, | 3341 int from, |
3341 int to) { | 3342 int to) { |
3342 ASSERT(from >= 0); | 3343 ASSERT(from >= 0); |
3343 int length = to - from; | 3344 int length = to - from; |
(...skipping 27 matching lines...) Expand all Loading... |
3371 ASSERT(length > 0); | 3372 ASSERT(length > 0); |
3372 AddElement(*string); | 3373 AddElement(*string); |
3373 if (!string->IsOneByteRepresentation()) { | 3374 if (!string->IsOneByteRepresentation()) { |
3374 is_ascii_ = false; | 3375 is_ascii_ = false; |
3375 } | 3376 } |
3376 IncrementCharacterCount(length); | 3377 IncrementCharacterCount(length); |
3377 } | 3378 } |
3378 | 3379 |
3379 | 3380 |
3380 Handle<String> ToString() { | 3381 Handle<String> ToString() { |
| 3382 if (overflowed_) { |
| 3383 heap_->isolate()->ThrowInvalidStringLength(); |
| 3384 return Handle<String>(); |
| 3385 } |
| 3386 |
3381 if (array_builder_.length() == 0) { | 3387 if (array_builder_.length() == 0) { |
3382 return heap_->isolate()->factory()->empty_string(); | 3388 return heap_->isolate()->factory()->empty_string(); |
3383 } | 3389 } |
3384 | 3390 |
3385 Handle<String> joined_string; | 3391 Handle<String> joined_string; |
3386 if (is_ascii_) { | 3392 if (is_ascii_) { |
3387 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); | 3393 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); |
3388 DisallowHeapAllocation no_gc; | 3394 DisallowHeapAllocation no_gc; |
3389 uint8_t* char_buffer = seq->GetChars(); | 3395 uint8_t* char_buffer = seq->GetChars(); |
3390 StringBuilderConcatHelper(*subject_, | 3396 StringBuilderConcatHelper(*subject_, |
(...skipping 11 matching lines...) Expand all Loading... |
3402 *array_builder_.array(), | 3408 *array_builder_.array(), |
3403 array_builder_.length()); | 3409 array_builder_.length()); |
3404 joined_string = Handle<String>::cast(seq); | 3410 joined_string = Handle<String>::cast(seq); |
3405 } | 3411 } |
3406 return joined_string; | 3412 return joined_string; |
3407 } | 3413 } |
3408 | 3414 |
3409 | 3415 |
3410 void IncrementCharacterCount(int by) { | 3416 void IncrementCharacterCount(int by) { |
3411 if (character_count_ > String::kMaxLength - by) { | 3417 if (character_count_ > String::kMaxLength - by) { |
3412 V8::FatalProcessOutOfMemory("String.replace result too large."); | 3418 overflowed_ = true; |
3413 } | 3419 } |
3414 character_count_ += by; | 3420 character_count_ += by; |
3415 } | 3421 } |
3416 | 3422 |
3417 private: | 3423 private: |
3418 Handle<SeqOneByteString> NewRawOneByteString(int length) { | 3424 Handle<SeqOneByteString> NewRawOneByteString(int length) { |
3419 return heap_->isolate()->factory()->NewRawOneByteString(length); | 3425 return heap_->isolate()->factory()->NewRawOneByteString(length); |
3420 } | 3426 } |
3421 | 3427 |
3422 | 3428 |
3423 Handle<SeqTwoByteString> NewRawTwoByteString(int length) { | 3429 Handle<SeqTwoByteString> NewRawTwoByteString(int length) { |
3424 return heap_->isolate()->factory()->NewRawTwoByteString(length); | 3430 return heap_->isolate()->factory()->NewRawTwoByteString(length); |
3425 } | 3431 } |
3426 | 3432 |
3427 | 3433 |
3428 void AddElement(Object* element) { | 3434 void AddElement(Object* element) { |
3429 ASSERT(element->IsSmi() || element->IsString()); | 3435 ASSERT(element->IsSmi() || element->IsString()); |
3430 ASSERT(array_builder_.capacity() > array_builder_.length()); | 3436 ASSERT(array_builder_.capacity() > array_builder_.length()); |
3431 array_builder_.Add(element); | 3437 array_builder_.Add(element); |
3432 } | 3438 } |
3433 | 3439 |
3434 Heap* heap_; | 3440 Heap* heap_; |
3435 FixedArrayBuilder array_builder_; | 3441 FixedArrayBuilder array_builder_; |
3436 Handle<String> subject_; | 3442 Handle<String> subject_; |
3437 int character_count_; | 3443 int character_count_; |
3438 bool is_ascii_; | 3444 bool is_ascii_; |
| 3445 bool overflowed_; |
3439 }; | 3446 }; |
3440 | 3447 |
3441 | 3448 |
3442 class CompiledReplacement { | 3449 class CompiledReplacement { |
3443 public: | 3450 public: |
3444 explicit CompiledReplacement(Zone* zone) | 3451 explicit CompiledReplacement(Zone* zone) |
3445 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} | 3452 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} |
3446 | 3453 |
3447 // Return whether the replacement is simple. | 3454 // Return whether the replacement is simple. |
3448 bool Compile(Handle<String> replacement, | 3455 bool Compile(Handle<String> replacement, |
(...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4027 if (prev < subject_length) { | 4034 if (prev < subject_length) { |
4028 builder.EnsureCapacity(2); | 4035 builder.EnsureCapacity(2); |
4029 builder.AddSubjectSlice(prev, subject_length); | 4036 builder.AddSubjectSlice(prev, subject_length); |
4030 } | 4037 } |
4031 | 4038 |
4032 RegExpImpl::SetLastMatchInfo(last_match_info, | 4039 RegExpImpl::SetLastMatchInfo(last_match_info, |
4033 subject, | 4040 subject, |
4034 capture_count, | 4041 capture_count, |
4035 global_cache.LastSuccessfulMatch()); | 4042 global_cache.LastSuccessfulMatch()); |
4036 | 4043 |
4037 return *(builder.ToString()); | 4044 Handle<String> result = builder.ToString(); |
| 4045 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 4046 return *result; |
4038 } | 4047 } |
4039 | 4048 |
4040 | 4049 |
4041 template <typename ResultSeqString> | 4050 template <typename ResultSeqString> |
4042 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( | 4051 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( |
4043 Isolate* isolate, | 4052 Isolate* isolate, |
4044 Handle<String> subject, | 4053 Handle<String> subject, |
4045 Handle<JSRegExp> regexp, | 4054 Handle<JSRegExp> regexp, |
4046 Handle<JSArray> last_match_info) { | 4055 Handle<JSArray> last_match_info) { |
4047 ASSERT(subject->IsFlat()); | 4056 ASSERT(subject->IsFlat()); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4173 ConsString* cons = ConsString::cast(*subject); | 4182 ConsString* cons = ConsString::cast(*subject); |
4174 Handle<String> first = Handle<String>(cons->first()); | 4183 Handle<String> first = Handle<String>(cons->first()); |
4175 Handle<String> second = Handle<String>(cons->second()); | 4184 Handle<String> second = Handle<String>(cons->second()); |
4176 Handle<String> new_first = | 4185 Handle<String> new_first = |
4177 StringReplaceOneCharWithString(isolate, | 4186 StringReplaceOneCharWithString(isolate, |
4178 first, | 4187 first, |
4179 search, | 4188 search, |
4180 replace, | 4189 replace, |
4181 found, | 4190 found, |
4182 recursion_limit - 1); | 4191 recursion_limit - 1); |
| 4192 if (new_first.is_null()) return new_first; |
4183 if (*found) return isolate->factory()->NewConsString(new_first, second); | 4193 if (*found) return isolate->factory()->NewConsString(new_first, second); |
4184 if (new_first.is_null()) return new_first; | |
4185 | 4194 |
4186 Handle<String> new_second = | 4195 Handle<String> new_second = |
4187 StringReplaceOneCharWithString(isolate, | 4196 StringReplaceOneCharWithString(isolate, |
4188 second, | 4197 second, |
4189 search, | 4198 search, |
4190 replace, | 4199 replace, |
4191 found, | 4200 found, |
4192 recursion_limit - 1); | 4201 recursion_limit - 1); |
| 4202 if (new_second.is_null()) return new_second; |
4193 if (*found) return isolate->factory()->NewConsString(first, new_second); | 4203 if (*found) return isolate->factory()->NewConsString(first, new_second); |
4194 if (new_second.is_null()) return new_second; | |
4195 | 4204 |
4196 return subject; | 4205 return subject; |
4197 } else { | 4206 } else { |
4198 int index = Runtime::StringMatch(isolate, subject, search, 0); | 4207 int index = Runtime::StringMatch(isolate, subject, search, 0); |
4199 if (index == -1) return subject; | 4208 if (index == -1) return subject; |
4200 *found = true; | 4209 *found = true; |
4201 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); | 4210 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); |
4202 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); | 4211 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); |
| 4212 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, cons1, Handle<String>()); |
4203 Handle<String> second = | 4213 Handle<String> second = |
4204 isolate->factory()->NewSubString(subject, index + 1, subject->length()); | 4214 isolate->factory()->NewSubString(subject, index + 1, subject->length()); |
4205 return isolate->factory()->NewConsString(cons1, second); | 4215 return isolate->factory()->NewConsString(cons1, second); |
4206 } | 4216 } |
4207 } | 4217 } |
4208 | 4218 |
4209 | 4219 |
4210 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { | 4220 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { |
4211 HandleScope scope(isolate); | 4221 HandleScope scope(isolate); |
4212 ASSERT(args.length() == 3); | 4222 ASSERT(args.length() == 3); |
4213 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 4223 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
4214 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); | 4224 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); |
4215 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); | 4225 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); |
4216 | 4226 |
4217 // If the cons string tree is too deep, we simply abort the recursion and | 4227 // If the cons string tree is too deep, we simply abort the recursion and |
4218 // retry with a flattened subject string. | 4228 // retry with a flattened subject string. |
4219 const int kRecursionLimit = 0x1000; | 4229 const int kRecursionLimit = 0x1000; |
4220 bool found = false; | 4230 bool found = false; |
4221 Handle<String> result = StringReplaceOneCharWithString(isolate, | 4231 Handle<String> result = StringReplaceOneCharWithString(isolate, |
4222 subject, | 4232 subject, |
4223 search, | 4233 search, |
4224 replace, | 4234 replace, |
4225 &found, | 4235 &found, |
4226 kRecursionLimit); | 4236 kRecursionLimit); |
4227 if (!result.is_null()) return *result; | 4237 if (!result.is_null()) return *result; |
| 4238 if (isolate->has_pending_exception()) return Failure::Exception(); |
4228 return *StringReplaceOneCharWithString(isolate, | 4239 return *StringReplaceOneCharWithString(isolate, |
4229 FlattenGetString(subject), | 4240 FlattenGetString(subject), |
4230 search, | 4241 search, |
4231 replace, | 4242 replace, |
4232 &found, | 4243 &found, |
4233 kRecursionLimit); | 4244 kRecursionLimit); |
4234 } | 4245 } |
4235 | 4246 |
4236 | 4247 |
4237 // Perform string match of pattern on subject, starting at start index. | 4248 // Perform string match of pattern on subject, starting at start index. |
(...skipping 1980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6218 | 6229 |
6219 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { | 6230 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { |
6220 HandleScope scope(isolate); | 6231 HandleScope scope(isolate); |
6221 ASSERT(args.length() == 1); | 6232 ASSERT(args.length() == 1); |
6222 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | 6233 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); |
6223 Handle<String> string = FlattenGetString(source); | 6234 Handle<String> string = FlattenGetString(source); |
6224 ASSERT(string->IsFlat()); | 6235 ASSERT(string->IsFlat()); |
6225 Handle<String> result = string->IsOneByteRepresentationUnderneath() | 6236 Handle<String> result = string->IsOneByteRepresentationUnderneath() |
6226 ? URIEscape::Escape<uint8_t>(isolate, source) | 6237 ? URIEscape::Escape<uint8_t>(isolate, source) |
6227 : URIEscape::Escape<uc16>(isolate, source); | 6238 : URIEscape::Escape<uc16>(isolate, source); |
6228 if (result.is_null()) return Failure::OutOfMemoryException(0x12); | 6239 RETURN_IF_EMPTY_HANDLE(isolate, result); |
6229 return *result; | 6240 return *result; |
6230 } | 6241 } |
6231 | 6242 |
6232 | 6243 |
6233 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { | 6244 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { |
6234 HandleScope scope(isolate); | 6245 HandleScope scope(isolate); |
6235 ASSERT(args.length() == 1); | 6246 ASSERT(args.length() == 1); |
6236 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | 6247 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); |
6237 Handle<String> string = FlattenGetString(source); | 6248 Handle<String> string = FlattenGetString(source); |
6238 ASSERT(string->IsFlat()); | 6249 ASSERT(string->IsFlat()); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6352 while (stream.HasMore()) { | 6363 while (stream.HasMore()) { |
6353 current = stream.GetNext(); | 6364 current = stream.GetNext(); |
6354 found_yuml |= (current == yuml_code); | 6365 found_yuml |= (current == yuml_code); |
6355 // NOTE: we use 0 as the next character here because, while | 6366 // NOTE: we use 0 as the next character here because, while |
6356 // the next character may affect what a character converts to, | 6367 // the next character may affect what a character converts to, |
6357 // it does not in any case affect the length of what it convert | 6368 // it does not in any case affect the length of what it convert |
6358 // to. | 6369 // to. |
6359 int char_length = mapping->get(current, 0, chars); | 6370 int char_length = mapping->get(current, 0, chars); |
6360 if (char_length == 0) char_length = 1; | 6371 if (char_length == 0) char_length = 1; |
6361 current_length += char_length; | 6372 current_length += char_length; |
6362 if (current_length > Smi::kMaxValue) { | 6373 if (current_length > String::kMaxLength) { |
6363 isolate->context()->mark_out_of_memory(); | 6374 AllowHeapAllocation allocate_error_and_return; |
6364 return Failure::OutOfMemoryException(0x13); | 6375 return isolate->ThrowInvalidStringLength(); |
6365 } | 6376 } |
6366 } | 6377 } |
6367 // Try again with the real length. Return signed if we need | 6378 // Try again with the real length. Return signed if we need |
6368 // to allocate a two-byte string for y-umlaut to uppercase. | 6379 // to allocate a two-byte string for y-umlaut to uppercase. |
6369 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) | 6380 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) |
6370 : Smi::FromInt(current_length); | 6381 : Smi::FromInt(current_length); |
6371 } else { | 6382 } else { |
6372 for (int j = 0; j < char_length; j++) { | 6383 for (int j = 0; j < char_length; j++) { |
6373 result->Set(i, chars[j]); | 6384 result->Set(i, chars[j]); |
6374 i++; | 6385 i++; |
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7009 return isolate->heap()->NumberFromInt32(x * y); | 7020 return isolate->heap()->NumberFromInt32(x * y); |
7010 } | 7021 } |
7011 | 7022 |
7012 | 7023 |
7013 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { | 7024 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { |
7014 HandleScope scope(isolate); | 7025 HandleScope scope(isolate); |
7015 ASSERT(args.length() == 2); | 7026 ASSERT(args.length() == 2); |
7016 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); | 7027 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); |
7017 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); | 7028 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); |
7018 isolate->counters()->string_add_runtime()->Increment(); | 7029 isolate->counters()->string_add_runtime()->Increment(); |
7019 return *isolate->factory()->NewConsString(str1, str2); | 7030 Handle<String> result = isolate->factory()->NewConsString(str1, str2); |
| 7031 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 7032 return *result; |
7020 } | 7033 } |
7021 | 7034 |
7022 | 7035 |
7023 template <typename sinkchar> | 7036 template <typename sinkchar> |
7024 static inline void StringBuilderConcatHelper(String* special, | 7037 static inline void StringBuilderConcatHelper(String* special, |
7025 sinkchar* sink, | 7038 sinkchar* sink, |
7026 FixedArray* fixed_array, | 7039 FixedArray* fixed_array, |
7027 int array_length) { | 7040 int array_length) { |
7028 int position = 0; | 7041 int position = 0; |
7029 for (int i = 0; i < array_length; i++) { | 7042 for (int i = 0; i < array_length; i++) { |
(...skipping 26 matching lines...) Expand all Loading... |
7056 position += element_length; | 7069 position += element_length; |
7057 } | 7070 } |
7058 } | 7071 } |
7059 } | 7072 } |
7060 | 7073 |
7061 | 7074 |
7062 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { | 7075 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { |
7063 HandleScope scope(isolate); | 7076 HandleScope scope(isolate); |
7064 ASSERT(args.length() == 3); | 7077 ASSERT(args.length() == 3); |
7065 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | 7078 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |
7066 if (!args[1]->IsSmi()) { | 7079 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); |
7067 isolate->context()->mark_out_of_memory(); | |
7068 return Failure::OutOfMemoryException(0x14); | |
7069 } | |
7070 int array_length = args.smi_at(1); | 7080 int array_length = args.smi_at(1); |
7071 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); | 7081 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); |
7072 | 7082 |
7073 // This assumption is used by the slice encoding in one or two smis. | 7083 // This assumption is used by the slice encoding in one or two smis. |
7074 ASSERT(Smi::kMaxValue >= String::kMaxLength); | 7084 ASSERT(Smi::kMaxValue >= String::kMaxLength); |
7075 | 7085 |
7076 JSObject::EnsureCanContainHeapObjectElements(array); | 7086 JSObject::EnsureCanContainHeapObjectElements(array); |
7077 | 7087 |
7078 int special_length = special->length(); | 7088 int special_length = special->length(); |
7079 if (!array->HasFastObjectElements()) { | 7089 if (!array->HasFastObjectElements()) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7133 int element_length = element->length(); | 7143 int element_length = element->length(); |
7134 increment = element_length; | 7144 increment = element_length; |
7135 if (one_byte && !element->HasOnlyOneByteChars()) { | 7145 if (one_byte && !element->HasOnlyOneByteChars()) { |
7136 one_byte = false; | 7146 one_byte = false; |
7137 } | 7147 } |
7138 } else { | 7148 } else { |
7139 ASSERT(!elt->IsTheHole()); | 7149 ASSERT(!elt->IsTheHole()); |
7140 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 7150 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
7141 } | 7151 } |
7142 if (increment > String::kMaxLength - position) { | 7152 if (increment > String::kMaxLength - position) { |
7143 isolate->context()->mark_out_of_memory(); | 7153 return isolate->ThrowInvalidStringLength(); |
7144 return Failure::OutOfMemoryException(0x15); | |
7145 } | 7154 } |
7146 position += increment; | 7155 position += increment; |
7147 } | 7156 } |
7148 | 7157 |
7149 int length = position; | 7158 int length = position; |
7150 Object* object; | 7159 Object* object; |
7151 | 7160 |
7152 if (one_byte) { | 7161 if (one_byte) { |
7153 { MaybeObject* maybe_object = | 7162 { MaybeObject* maybe_object = |
7154 isolate->heap()->AllocateRawOneByteString(length); | 7163 isolate->heap()->AllocateRawOneByteString(length); |
(...skipping 14 matching lines...) Expand all Loading... |
7169 StringBuilderConcatHelper(*special, | 7178 StringBuilderConcatHelper(*special, |
7170 answer->GetChars(), | 7179 answer->GetChars(), |
7171 fixed_array, | 7180 fixed_array, |
7172 array_length); | 7181 array_length); |
7173 return answer; | 7182 return answer; |
7174 } | 7183 } |
7175 } | 7184 } |
7176 | 7185 |
7177 | 7186 |
7178 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { | 7187 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { |
7179 SealHandleScope shs(isolate); | 7188 HandleScope scope(isolate); |
7180 ASSERT(args.length() == 3); | 7189 ASSERT(args.length() == 3); |
7181 CONVERT_ARG_CHECKED(JSArray, array, 0); | 7190 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |
7182 if (!args[1]->IsSmi()) { | 7191 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); |
7183 isolate->context()->mark_out_of_memory(); | |
7184 return Failure::OutOfMemoryException(0x16); | |
7185 } | |
7186 int array_length = args.smi_at(1); | 7192 int array_length = args.smi_at(1); |
7187 CONVERT_ARG_CHECKED(String, separator, 2); | 7193 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); |
| 7194 RUNTIME_ASSERT(array->HasFastObjectElements()); |
7188 | 7195 |
7189 if (!array->HasFastObjectElements()) { | 7196 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); |
7190 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
7191 } | |
7192 FixedArray* fixed_array = FixedArray::cast(array->elements()); | |
7193 if (fixed_array->length() < array_length) { | 7197 if (fixed_array->length() < array_length) { |
7194 array_length = fixed_array->length(); | 7198 array_length = fixed_array->length(); |
7195 } | 7199 } |
7196 | 7200 |
7197 if (array_length == 0) { | 7201 if (array_length == 0) { |
7198 return isolate->heap()->empty_string(); | 7202 return isolate->heap()->empty_string(); |
7199 } else if (array_length == 1) { | 7203 } else if (array_length == 1) { |
7200 Object* first = fixed_array->get(0); | 7204 Object* first = fixed_array->get(0); |
7201 if (first->IsString()) return first; | 7205 RUNTIME_ASSERT(first->IsString()); |
| 7206 return first; |
7202 } | 7207 } |
7203 | 7208 |
7204 int separator_length = separator->length(); | 7209 int separator_length = separator->length(); |
7205 int max_nof_separators = | 7210 int max_nof_separators = |
7206 (String::kMaxLength + separator_length - 1) / separator_length; | 7211 (String::kMaxLength + separator_length - 1) / separator_length; |
7207 if (max_nof_separators < (array_length - 1)) { | 7212 if (max_nof_separators < (array_length - 1)) { |
7208 isolate->context()->mark_out_of_memory(); | 7213 return isolate->ThrowInvalidStringLength(); |
7209 return Failure::OutOfMemoryException(0x17); | |
7210 } | 7214 } |
7211 int length = (array_length - 1) * separator_length; | 7215 int length = (array_length - 1) * separator_length; |
7212 for (int i = 0; i < array_length; i++) { | 7216 for (int i = 0; i < array_length; i++) { |
7213 Object* element_obj = fixed_array->get(i); | 7217 Object* element_obj = fixed_array->get(i); |
7214 if (!element_obj->IsString()) { | 7218 RUNTIME_ASSERT(element_obj->IsString()); |
7215 // TODO(1161): handle this case. | |
7216 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
7217 } | |
7218 String* element = String::cast(element_obj); | 7219 String* element = String::cast(element_obj); |
7219 int increment = element->length(); | 7220 int increment = element->length(); |
7220 if (increment > String::kMaxLength - length) { | 7221 if (increment > String::kMaxLength - length) { |
7221 isolate->context()->mark_out_of_memory(); | 7222 return isolate->ThrowInvalidStringLength(); |
7222 return Failure::OutOfMemoryException(0x18); | |
7223 } | 7223 } |
7224 length += increment; | 7224 length += increment; |
7225 } | 7225 } |
7226 | 7226 |
7227 Object* object; | 7227 Handle<SeqTwoByteString> answer = |
7228 { MaybeObject* maybe_object = | 7228 isolate->factory()->NewRawTwoByteString(length); |
7229 isolate->heap()->AllocateRawTwoByteString(length); | 7229 |
7230 if (!maybe_object->ToObject(&object)) return maybe_object; | 7230 DisallowHeapAllocation no_gc; |
7231 } | |
7232 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | |
7233 | 7231 |
7234 uc16* sink = answer->GetChars(); | 7232 uc16* sink = answer->GetChars(); |
7235 #ifdef DEBUG | 7233 #ifdef DEBUG |
7236 uc16* end = sink + length; | 7234 uc16* end = sink + length; |
7237 #endif | 7235 #endif |
7238 | 7236 |
7239 String* first = String::cast(fixed_array->get(0)); | 7237 String* first = String::cast(fixed_array->get(0)); |
| 7238 String* seperator_raw = *separator; |
7240 int first_length = first->length(); | 7239 int first_length = first->length(); |
7241 String::WriteToFlat(first, sink, 0, first_length); | 7240 String::WriteToFlat(first, sink, 0, first_length); |
7242 sink += first_length; | 7241 sink += first_length; |
7243 | 7242 |
7244 for (int i = 1; i < array_length; i++) { | 7243 for (int i = 1; i < array_length; i++) { |
7245 ASSERT(sink + separator_length <= end); | 7244 ASSERT(sink + separator_length <= end); |
7246 String::WriteToFlat(separator, sink, 0, separator_length); | 7245 String::WriteToFlat(seperator_raw, sink, 0, separator_length); |
7247 sink += separator_length; | 7246 sink += separator_length; |
7248 | 7247 |
7249 String* element = String::cast(fixed_array->get(i)); | 7248 String* element = String::cast(fixed_array->get(i)); |
7250 int element_length = element->length(); | 7249 int element_length = element->length(); |
7251 ASSERT(sink + element_length <= end); | 7250 ASSERT(sink + element_length <= end); |
7252 String::WriteToFlat(element, sink, 0, element_length); | 7251 String::WriteToFlat(element, sink, 0, element_length); |
7253 sink += element_length; | 7252 sink += element_length; |
7254 } | 7253 } |
7255 ASSERT(sink == end); | 7254 ASSERT(sink == end); |
7256 | 7255 |
7257 // Use %_FastAsciiArrayJoin instead. | 7256 // Use %_FastAsciiArrayJoin instead. |
7258 ASSERT(!answer->IsOneByteRepresentation()); | 7257 ASSERT(!answer->IsOneByteRepresentation()); |
7259 return answer; | 7258 return *answer; |
7260 } | 7259 } |
7261 | 7260 |
7262 template <typename Char> | 7261 template <typename Char> |
7263 static void JoinSparseArrayWithSeparator(FixedArray* elements, | 7262 static void JoinSparseArrayWithSeparator(FixedArray* elements, |
7264 int elements_length, | 7263 int elements_length, |
7265 uint32_t array_length, | 7264 uint32_t array_length, |
7266 String* separator, | 7265 String* separator, |
7267 Vector<Char> buffer) { | 7266 Vector<Char> buffer) { |
7268 int previous_separator_position = 0; | 7267 int previous_separator_position = 0; |
7269 int separator_length = separator->length(); | 7268 int separator_length = separator->length(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7350 // Nonempty separator and at least 2^31-1 separators necessary | 7349 // Nonempty separator and at least 2^31-1 separators necessary |
7351 // means that the string is too large to create. | 7350 // means that the string is too large to create. |
7352 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 7351 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
7353 overflow = true; | 7352 overflow = true; |
7354 } | 7353 } |
7355 } | 7354 } |
7356 if (overflow) { | 7355 if (overflow) { |
7357 // Throw an exception if the resulting string is too large. See | 7356 // Throw an exception if the resulting string is too large. See |
7358 // https://code.google.com/p/chromium/issues/detail?id=336820 | 7357 // https://code.google.com/p/chromium/issues/detail?id=336820 |
7359 // for details. | 7358 // for details. |
7360 return isolate->Throw(*isolate->factory()-> | 7359 return isolate->ThrowInvalidStringLength(); |
7361 NewRangeError("invalid_string_length", | |
7362 HandleVector<Object>(NULL, 0))); | |
7363 } | 7360 } |
7364 | 7361 |
7365 if (is_ascii) { | 7362 if (is_ascii) { |
7366 MaybeObject* result_allocation = | 7363 MaybeObject* result_allocation = |
7367 isolate->heap()->AllocateRawOneByteString(string_length); | 7364 isolate->heap()->AllocateRawOneByteString(string_length); |
7368 if (result_allocation->IsFailure()) return result_allocation; | 7365 if (result_allocation->IsFailure()) return result_allocation; |
7369 SeqOneByteString* result_string = | 7366 SeqOneByteString* result_string = |
7370 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); | 7367 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); |
7371 JoinSparseArrayWithSeparator<uint8_t>(elements, | 7368 JoinSparseArrayWithSeparator<uint8_t>(elements, |
7372 elements_length, | 7369 elements_length, |
(...skipping 7666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15039 // Handle last resort GC and make sure to allow future allocations | 15036 // Handle last resort GC and make sure to allow future allocations |
15040 // to grow the heap without causing GCs (if possible). | 15037 // to grow the heap without causing GCs (if possible). |
15041 isolate->counters()->gc_last_resort_from_js()->Increment(); | 15038 isolate->counters()->gc_last_resort_from_js()->Increment(); |
15042 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 15039 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
15043 "Runtime::PerformGC"); | 15040 "Runtime::PerformGC"); |
15044 } | 15041 } |
15045 } | 15042 } |
15046 | 15043 |
15047 | 15044 |
15048 } } // namespace v8::internal | 15045 } } // namespace v8::internal |
OLD | NEW |