| 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 |