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 3 // found in the LICENSE file. 4 5 #include "src/string-builder.h" 6 7 #include "src/isolate-inl.h" 8 #include "src/objects-inl.h" 9 10 namespace v8 { 11 namespace internal { 12 13 MaybeHandle<String> ReplacementStringBuilder::ToString() { 14 Isolate* isolate = heap_->isolate(); 15 if (array_builder_.length() == 0) { 16 return isolate->factory()->empty_string(); 17 } 18 19 Handle<String> joined_string; 20 if (is_one_byte_) { 21 Handle<SeqOneByteString> seq; 22 ASSIGN_RETURN_ON_EXCEPTION( 23 isolate, seq, isolate->factory()->NewRawOneByteString(character_count_), 24 String); 25 26 DisallowHeapAllocation no_gc; 27 uint8_t* char_buffer = seq->GetChars(); 28 StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), 29 array_builder_.length()); 30 joined_string = Handle<String>::cast(seq); 31 } else { 32 // Two-byte. 33 Handle<SeqTwoByteString> seq; 34 ASSIGN_RETURN_ON_EXCEPTION( 35 isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_), 36 String); 37 38 DisallowHeapAllocation no_gc; 39 uc16* char_buffer = seq->GetChars(); 40 StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), 41 array_builder_.length()); 42 joined_string = Handle<String>::cast(seq); 43 } 44 return joined_string; 45 } 46 47 48 IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate) 49 : isolate_(isolate), 50 encoding_(String::ONE_BYTE_ENCODING), 51 overflowed_(false), 52 part_length_(kInitialPartLength), 53 current_index_(0) { 54 // Create an accumulator handle starting with the empty string. 55 accumulator_ = Handle<String>::New(isolate->heap()->empty_string(), isolate); 56 current_part_ = 57 factory()->NewRawOneByteString(part_length_).ToHandleChecked(); 58 } 59 60 61 void IncrementalStringBuilder::Accumulate(Handle<String> new_part) { 62 Handle<String> new_accumulator; 63 if (accumulator()->length() + new_part->length() > String::kMaxLength) { 64 // Set the flag and carry on. Delay throwing the exception till the end. 65 new_accumulator = factory()->empty_string(); 66 overflowed_ = true; 67 } else { 68 new_accumulator = 69 factory()->NewConsString(accumulator(), new_part).ToHandleChecked(); 70 } 71 set_accumulator(new_accumulator); 72 } 73 74 75 void IncrementalStringBuilder::Extend() { 76 DCHECK_EQ(current_index_, current_part()->length()); 77 Accumulate(current_part()); 78 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { 79 part_length_ *= kPartLengthGrowthFactor; 80 } 81 Handle<String> new_part; 82 if (encoding_ == String::ONE_BYTE_ENCODING) { 83 new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked(); 84 } else { 85 new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked(); 86 } 87 // Reuse the same handle to avoid being invalidated when exiting handle scope. 88 set_current_part(new_part); 89 current_index_ = 0; 90 } 91 92 93 MaybeHandle<String> IncrementalStringBuilder::Finish() { 94 ShrinkCurrentPart(); 95 Accumulate(current_part()); 96 if (overflowed_) { 97 THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String); 98 } 99 return accumulator(); 100 } 101 102 103 void IncrementalStringBuilder::AppendString(Handle<String> string) { 104 ShrinkCurrentPart(); 105 part_length_ = kInitialPartLength; // Allocate conservatively. 106 Extend(); // Attach current part and allocate new part. 107 Accumulate(string); 108 } 109 } // namespace internal 110 } // namespace v8 111