OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_RUNTIME_STRING_BUILDER_H_ | 5 #ifndef V8_STRING_BUILDER_H_ |
6 #define V8_RUNTIME_STRING_BUILDER_H_ | 6 #define V8_STRING_BUILDER_H_ |
| 7 |
| 8 #include "src/v8.h" |
7 | 9 |
8 namespace v8 { | 10 namespace v8 { |
9 namespace internal { | 11 namespace internal { |
10 | 12 |
11 const int kStringBuilderConcatHelperLengthBits = 11; | 13 const int kStringBuilderConcatHelperLengthBits = 11; |
12 const int kStringBuilderConcatHelperPositionBits = 19; | 14 const int kStringBuilderConcatHelperPositionBits = 19; |
13 | 15 |
14 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> | 16 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> |
15 StringBuilderSubstringLength; | 17 StringBuilderSubstringLength; |
16 typedef BitField<int, kStringBuilderConcatHelperLengthBits, | 18 typedef BitField<int, kStringBuilderConcatHelperLengthBits, |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 int length = string->length(); | 228 int length = string->length(); |
227 DCHECK(length > 0); | 229 DCHECK(length > 0); |
228 AddElement(*string); | 230 AddElement(*string); |
229 if (!string->IsOneByteRepresentation()) { | 231 if (!string->IsOneByteRepresentation()) { |
230 is_one_byte_ = false; | 232 is_one_byte_ = false; |
231 } | 233 } |
232 IncrementCharacterCount(length); | 234 IncrementCharacterCount(length); |
233 } | 235 } |
234 | 236 |
235 | 237 |
236 MaybeHandle<String> ToString() { | 238 MaybeHandle<String> ToString(); |
237 Isolate* isolate = heap_->isolate(); | |
238 if (array_builder_.length() == 0) { | |
239 return isolate->factory()->empty_string(); | |
240 } | |
241 | |
242 Handle<String> joined_string; | |
243 if (is_one_byte_) { | |
244 Handle<SeqOneByteString> seq; | |
245 ASSIGN_RETURN_ON_EXCEPTION( | |
246 isolate, seq, | |
247 isolate->factory()->NewRawOneByteString(character_count_), String); | |
248 | |
249 DisallowHeapAllocation no_gc; | |
250 uint8_t* char_buffer = seq->GetChars(); | |
251 StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), | |
252 array_builder_.length()); | |
253 joined_string = Handle<String>::cast(seq); | |
254 } else { | |
255 // Two-byte. | |
256 Handle<SeqTwoByteString> seq; | |
257 ASSIGN_RETURN_ON_EXCEPTION( | |
258 isolate, seq, | |
259 isolate->factory()->NewRawTwoByteString(character_count_), String); | |
260 | |
261 DisallowHeapAllocation no_gc; | |
262 uc16* char_buffer = seq->GetChars(); | |
263 StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), | |
264 array_builder_.length()); | |
265 joined_string = Handle<String>::cast(seq); | |
266 } | |
267 return joined_string; | |
268 } | |
269 | 239 |
270 | 240 |
271 void IncrementCharacterCount(int by) { | 241 void IncrementCharacterCount(int by) { |
272 if (character_count_ > String::kMaxLength - by) { | 242 if (character_count_ > String::kMaxLength - by) { |
273 STATIC_ASSERT(String::kMaxLength < kMaxInt); | 243 STATIC_ASSERT(String::kMaxLength < kMaxInt); |
274 character_count_ = kMaxInt; | 244 character_count_ = kMaxInt; |
275 } else { | 245 } else { |
276 character_count_ += by; | 246 character_count_ += by; |
277 } | 247 } |
278 } | 248 } |
279 | 249 |
280 private: | 250 private: |
281 void AddElement(Object* element) { | 251 void AddElement(Object* element) { |
282 DCHECK(element->IsSmi() || element->IsString()); | 252 DCHECK(element->IsSmi() || element->IsString()); |
283 DCHECK(array_builder_.capacity() > array_builder_.length()); | 253 DCHECK(array_builder_.capacity() > array_builder_.length()); |
284 array_builder_.Add(element); | 254 array_builder_.Add(element); |
285 } | 255 } |
286 | 256 |
287 Heap* heap_; | 257 Heap* heap_; |
288 FixedArrayBuilder array_builder_; | 258 FixedArrayBuilder array_builder_; |
289 Handle<String> subject_; | 259 Handle<String> subject_; |
290 int character_count_; | 260 int character_count_; |
291 bool is_one_byte_; | 261 bool is_one_byte_; |
292 }; | 262 }; |
| 263 |
| 264 |
| 265 class IncrementalStringBuilder { |
| 266 public: |
| 267 explicit IncrementalStringBuilder(Isolate* isolate); |
| 268 |
| 269 INLINE(String::Encoding CurrentEncoding()) { return encoding_; } |
| 270 |
| 271 template <typename SrcChar, typename DestChar> |
| 272 INLINE(void Append(SrcChar c)); |
| 273 |
| 274 INLINE(void AppendCharacter(uint8_t c)) { |
| 275 if (encoding_ == String::ONE_BYTE_ENCODING) { |
| 276 Append<uint8_t, uint8_t>(c); |
| 277 } else { |
| 278 Append<uint8_t, uc16>(c); |
| 279 } |
| 280 } |
| 281 |
| 282 INLINE(void AppendCString(const char* s)) { |
| 283 const uint8_t* u = reinterpret_cast<const uint8_t*>(s); |
| 284 if (encoding_ == String::ONE_BYTE_ENCODING) { |
| 285 while (*u != '\0') Append<uint8_t, uint8_t>(*(u++)); |
| 286 } else { |
| 287 while (*u != '\0') Append<uint8_t, uc16>(*(u++)); |
| 288 } |
| 289 } |
| 290 |
| 291 INLINE(bool CurrentPartCanFit(int length)) { |
| 292 return part_length_ - current_index_ > length; |
| 293 } |
| 294 |
| 295 void AppendString(Handle<String> string); |
| 296 |
| 297 MaybeHandle<String> Finish(); |
| 298 |
| 299 // Change encoding to two-byte. |
| 300 void ChangeEncoding() { |
| 301 DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_); |
| 302 ShrinkCurrentPart(); |
| 303 encoding_ = String::TWO_BYTE_ENCODING; |
| 304 Extend(); |
| 305 } |
| 306 |
| 307 template <typename DestChar> |
| 308 class NoExtend { |
| 309 public: |
| 310 explicit NoExtend(Handle<String> string, int offset) { |
| 311 DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString()); |
| 312 if (sizeof(DestChar) == 1) { |
| 313 start_ = reinterpret_cast<DestChar*>( |
| 314 Handle<SeqOneByteString>::cast(string)->GetChars() + offset); |
| 315 } else { |
| 316 start_ = reinterpret_cast<DestChar*>( |
| 317 Handle<SeqTwoByteString>::cast(string)->GetChars() + offset); |
| 318 } |
| 319 cursor_ = start_; |
| 320 } |
| 321 |
| 322 INLINE(void Append(DestChar c)) { *(cursor_++) = c; } |
| 323 INLINE(void AppendCString(const char* s)) { |
| 324 const uint8_t* u = reinterpret_cast<const uint8_t*>(s); |
| 325 while (*u != '\0') Append(*(u++)); |
| 326 } |
| 327 |
| 328 int written() { return cursor_ - start_; } |
| 329 |
| 330 private: |
| 331 DestChar* start_; |
| 332 DestChar* cursor_; |
| 333 DisallowHeapAllocation no_gc_; |
| 334 }; |
| 335 |
| 336 template <typename DestChar> |
| 337 class NoExtendString : public NoExtend<DestChar> { |
| 338 public: |
| 339 NoExtendString(Handle<String> string, int required_length) |
| 340 : NoExtend<DestChar>(string, 0), string_(string) { |
| 341 DCHECK(string->length() >= required_length); |
| 342 } |
| 343 |
| 344 ~NoExtendString() { |
| 345 Handle<SeqString> string = Handle<SeqString>::cast(string_); |
| 346 int length = NoExtend<DestChar>::written(); |
| 347 *string_.location() = *SeqString::Truncate(string, length); |
| 348 } |
| 349 |
| 350 private: |
| 351 Handle<String> string_; |
| 352 }; |
| 353 |
| 354 template <typename DestChar> |
| 355 class NoExtendBuilder : public NoExtend<DestChar> { |
| 356 public: |
| 357 NoExtendBuilder(IncrementalStringBuilder* builder, int required_length) |
| 358 : NoExtend<DestChar>(builder->current_part(), builder->current_index_), |
| 359 builder_(builder) { |
| 360 DCHECK(builder->CurrentPartCanFit(required_length)); |
| 361 } |
| 362 |
| 363 ~NoExtendBuilder() { |
| 364 builder_->current_index_ += NoExtend<DestChar>::written(); |
| 365 } |
| 366 |
| 367 private: |
| 368 IncrementalStringBuilder* builder_; |
| 369 }; |
| 370 |
| 371 private: |
| 372 Factory* factory() { return isolate_->factory(); } |
| 373 |
| 374 INLINE(Handle<String> accumulator()) { return accumulator_; } |
| 375 |
| 376 INLINE(void set_accumulator(Handle<String> string)) { |
| 377 *accumulator_.location() = *string; |
| 378 } |
| 379 |
| 380 INLINE(Handle<String> current_part()) { return current_part_; } |
| 381 |
| 382 INLINE(void set_current_part(Handle<String> string)) { |
| 383 *current_part_.location() = *string; |
| 384 } |
| 385 |
| 386 // Add the current part to the accumulator. |
| 387 void Accumulate(); |
| 388 |
| 389 // Finish the current part and allocate a new part. |
| 390 void Extend(); |
| 391 |
| 392 // Shrink current part to the right size. |
| 393 void ShrinkCurrentPart() { |
| 394 DCHECK(current_index_ < part_length_); |
| 395 set_current_part(SeqString::Truncate( |
| 396 Handle<SeqString>::cast(current_part()), current_index_)); |
| 397 } |
| 398 |
| 399 static const int kInitialPartLength = 32; |
| 400 static const int kMaxPartLength = 16 * 1024; |
| 401 static const int kPartLengthGrowthFactor = 2; |
| 402 |
| 403 Isolate* isolate_; |
| 404 String::Encoding encoding_; |
| 405 bool overflowed_; |
| 406 int part_length_; |
| 407 int current_index_; |
| 408 Handle<String> accumulator_; |
| 409 Handle<String> current_part_; |
| 410 }; |
| 411 |
| 412 |
| 413 template <typename SrcChar, typename DestChar> |
| 414 void IncrementalStringBuilder::Append(SrcChar c) { |
| 415 DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1); |
| 416 if (sizeof(DestChar) == 1) { |
| 417 DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_); |
| 418 SeqOneByteString::cast(*current_part_) |
| 419 ->SeqOneByteStringSet(current_index_++, c); |
| 420 } else { |
| 421 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_); |
| 422 SeqTwoByteString::cast(*current_part_) |
| 423 ->SeqTwoByteStringSet(current_index_++, c); |
| 424 } |
| 425 if (current_index_ == part_length_) Extend(); |
| 426 } |
293 } | 427 } |
294 } // namespace v8::internal | 428 } // namespace v8::internal |
295 | 429 |
296 #endif // V8_RUNTIME_STRING_BUILDER_H_ | 430 #endif // V8_STRING_BUILDER_H_ |
OLD | NEW |