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 return isolate->ThrowInvalidStringLength(); |
6364 return Failure::OutOfMemoryException(0x13); | |
6365 } | 6375 } |
6366 } | 6376 } |
6367 // Try again with the real length. Return signed if we need | 6377 // Try again with the real length. Return signed if we need |
6368 // to allocate a two-byte string for y-umlaut to uppercase. | 6378 // to allocate a two-byte string for y-umlaut to uppercase. |
6369 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) | 6379 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) |
6370 : Smi::FromInt(current_length); | 6380 : Smi::FromInt(current_length); |
6371 } else { | 6381 } else { |
6372 for (int j = 0; j < char_length; j++) { | 6382 for (int j = 0; j < char_length; j++) { |
6373 result->Set(i, chars[j]); | 6383 result->Set(i, chars[j]); |
6374 i++; | 6384 i++; |
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7009 return isolate->heap()->NumberFromInt32(x * y); | 7019 return isolate->heap()->NumberFromInt32(x * y); |
7010 } | 7020 } |
7011 | 7021 |
7012 | 7022 |
7013 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { | 7023 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { |
7014 HandleScope scope(isolate); | 7024 HandleScope scope(isolate); |
7015 ASSERT(args.length() == 2); | 7025 ASSERT(args.length() == 2); |
7016 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); | 7026 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); |
7017 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); | 7027 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); |
7018 isolate->counters()->string_add_runtime()->Increment(); | 7028 isolate->counters()->string_add_runtime()->Increment(); |
7019 return *isolate->factory()->NewConsString(str1, str2); | 7029 Handle<String> result = isolate->factory()->NewConsString(str1, str2); |
| 7030 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 7031 return *result; |
7020 } | 7032 } |
7021 | 7033 |
7022 | 7034 |
7023 template <typename sinkchar> | 7035 template <typename sinkchar> |
7024 static inline void StringBuilderConcatHelper(String* special, | 7036 static inline void StringBuilderConcatHelper(String* special, |
7025 sinkchar* sink, | 7037 sinkchar* sink, |
7026 FixedArray* fixed_array, | 7038 FixedArray* fixed_array, |
7027 int array_length) { | 7039 int array_length) { |
7028 int position = 0; | 7040 int position = 0; |
7029 for (int i = 0; i < array_length; i++) { | 7041 for (int i = 0; i < array_length; i++) { |
(...skipping 26 matching lines...) Expand all Loading... |
7056 position += element_length; | 7068 position += element_length; |
7057 } | 7069 } |
7058 } | 7070 } |
7059 } | 7071 } |
7060 | 7072 |
7061 | 7073 |
7062 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { | 7074 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { |
7063 HandleScope scope(isolate); | 7075 HandleScope scope(isolate); |
7064 ASSERT(args.length() == 3); | 7076 ASSERT(args.length() == 3); |
7065 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | 7077 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |
7066 if (!args[1]->IsSmi()) { | 7078 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); | 7079 int array_length = args.smi_at(1); |
7071 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); | 7080 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); |
7072 | 7081 |
7073 // This assumption is used by the slice encoding in one or two smis. | 7082 // This assumption is used by the slice encoding in one or two smis. |
7074 ASSERT(Smi::kMaxValue >= String::kMaxLength); | 7083 ASSERT(Smi::kMaxValue >= String::kMaxLength); |
7075 | 7084 |
7076 JSObject::EnsureCanContainHeapObjectElements(array); | 7085 JSObject::EnsureCanContainHeapObjectElements(array); |
7077 | 7086 |
7078 int special_length = special->length(); | 7087 int special_length = special->length(); |
7079 if (!array->HasFastObjectElements()) { | 7088 if (!array->HasFastObjectElements()) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7133 int element_length = element->length(); | 7142 int element_length = element->length(); |
7134 increment = element_length; | 7143 increment = element_length; |
7135 if (one_byte && !element->HasOnlyOneByteChars()) { | 7144 if (one_byte && !element->HasOnlyOneByteChars()) { |
7136 one_byte = false; | 7145 one_byte = false; |
7137 } | 7146 } |
7138 } else { | 7147 } else { |
7139 ASSERT(!elt->IsTheHole()); | 7148 ASSERT(!elt->IsTheHole()); |
7140 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 7149 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
7141 } | 7150 } |
7142 if (increment > String::kMaxLength - position) { | 7151 if (increment > String::kMaxLength - position) { |
7143 isolate->context()->mark_out_of_memory(); | 7152 return isolate->ThrowInvalidStringLength(); |
7144 return Failure::OutOfMemoryException(0x15); | |
7145 } | 7153 } |
7146 position += increment; | 7154 position += increment; |
7147 } | 7155 } |
7148 | 7156 |
7149 int length = position; | 7157 int length = position; |
7150 Object* object; | 7158 Object* object; |
7151 | 7159 |
7152 if (one_byte) { | 7160 if (one_byte) { |
7153 { MaybeObject* maybe_object = | 7161 { MaybeObject* maybe_object = |
7154 isolate->heap()->AllocateRawOneByteString(length); | 7162 isolate->heap()->AllocateRawOneByteString(length); |
(...skipping 17 matching lines...) Expand all Loading... |
7172 array_length); | 7180 array_length); |
7173 return answer; | 7181 return answer; |
7174 } | 7182 } |
7175 } | 7183 } |
7176 | 7184 |
7177 | 7185 |
7178 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { | 7186 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { |
7179 SealHandleScope shs(isolate); | 7187 SealHandleScope shs(isolate); |
7180 ASSERT(args.length() == 3); | 7188 ASSERT(args.length() == 3); |
7181 CONVERT_ARG_CHECKED(JSArray, array, 0); | 7189 CONVERT_ARG_CHECKED(JSArray, array, 0); |
7182 if (!args[1]->IsSmi()) { | 7190 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); | 7191 int array_length = args.smi_at(1); |
7187 CONVERT_ARG_CHECKED(String, separator, 2); | 7192 CONVERT_ARG_CHECKED(String, separator, 2); |
7188 | 7193 |
7189 if (!array->HasFastObjectElements()) { | 7194 if (!array->HasFastObjectElements()) { |
7190 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 7195 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
7191 } | 7196 } |
7192 FixedArray* fixed_array = FixedArray::cast(array->elements()); | 7197 FixedArray* fixed_array = FixedArray::cast(array->elements()); |
7193 if (fixed_array->length() < array_length) { | 7198 if (fixed_array->length() < array_length) { |
7194 array_length = fixed_array->length(); | 7199 array_length = fixed_array->length(); |
7195 } | 7200 } |
7196 | 7201 |
7197 if (array_length == 0) { | 7202 if (array_length == 0) { |
7198 return isolate->heap()->empty_string(); | 7203 return isolate->heap()->empty_string(); |
7199 } else if (array_length == 1) { | 7204 } else if (array_length == 1) { |
7200 Object* first = fixed_array->get(0); | 7205 Object* first = fixed_array->get(0); |
7201 if (first->IsString()) return first; | 7206 if (first->IsString()) 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 if (!element_obj->IsString()) { |
7215 // TODO(1161): handle this case. | 7219 // TODO(1161): handle this case. |
7216 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 7220 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
7217 } | 7221 } |
7218 String* element = String::cast(element_obj); | 7222 String* element = String::cast(element_obj); |
7219 int increment = element->length(); | 7223 int increment = element->length(); |
7220 if (increment > String::kMaxLength - length) { | 7224 if (increment > String::kMaxLength - length) { |
7221 isolate->context()->mark_out_of_memory(); | 7225 return isolate->ThrowInvalidStringLength(); |
7222 return Failure::OutOfMemoryException(0x18); | |
7223 } | 7226 } |
7224 length += increment; | 7227 length += increment; |
7225 } | 7228 } |
7226 | 7229 |
7227 Object* object; | 7230 Object* object; |
7228 { MaybeObject* maybe_object = | 7231 { MaybeObject* maybe_object = |
7229 isolate->heap()->AllocateRawTwoByteString(length); | 7232 isolate->heap()->AllocateRawTwoByteString(length); |
7230 if (!maybe_object->ToObject(&object)) return maybe_object; | 7233 if (!maybe_object->ToObject(&object)) return maybe_object; |
7231 } | 7234 } |
7232 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 7235 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7350 // Nonempty separator and at least 2^31-1 separators necessary | 7353 // Nonempty separator and at least 2^31-1 separators necessary |
7351 // means that the string is too large to create. | 7354 // means that the string is too large to create. |
7352 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 7355 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
7353 overflow = true; | 7356 overflow = true; |
7354 } | 7357 } |
7355 } | 7358 } |
7356 if (overflow) { | 7359 if (overflow) { |
7357 // Throw an exception if the resulting string is too large. See | 7360 // Throw an exception if the resulting string is too large. See |
7358 // https://code.google.com/p/chromium/issues/detail?id=336820 | 7361 // https://code.google.com/p/chromium/issues/detail?id=336820 |
7359 // for details. | 7362 // for details. |
7360 return isolate->Throw(*isolate->factory()-> | 7363 return isolate->ThrowInvalidStringLength(); |
7361 NewRangeError("invalid_string_length", | |
7362 HandleVector<Object>(NULL, 0))); | |
7363 } | 7364 } |
7364 | 7365 |
7365 if (is_ascii) { | 7366 if (is_ascii) { |
7366 MaybeObject* result_allocation = | 7367 MaybeObject* result_allocation = |
7367 isolate->heap()->AllocateRawOneByteString(string_length); | 7368 isolate->heap()->AllocateRawOneByteString(string_length); |
7368 if (result_allocation->IsFailure()) return result_allocation; | 7369 if (result_allocation->IsFailure()) return result_allocation; |
7369 SeqOneByteString* result_string = | 7370 SeqOneByteString* result_string = |
7370 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); | 7371 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); |
7371 JoinSparseArrayWithSeparator<uint8_t>(elements, | 7372 JoinSparseArrayWithSeparator<uint8_t>(elements, |
7372 elements_length, | 7373 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 | 15040 // Handle last resort GC and make sure to allow future allocations |
15040 // to grow the heap without causing GCs (if possible). | 15041 // to grow the heap without causing GCs (if possible). |
15041 isolate->counters()->gc_last_resort_from_js()->Increment(); | 15042 isolate->counters()->gc_last_resort_from_js()->Increment(); |
15042 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 15043 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
15043 "Runtime::PerformGC"); | 15044 "Runtime::PerformGC"); |
15044 } | 15045 } |
15045 } | 15046 } |
15046 | 15047 |
15047 | 15048 |
15048 } } // namespace v8::internal | 15049 } } // namespace v8::internal |
OLD | NEW |