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