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 
ToString()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 
IncrementalStringBuilder(Isolate * isolate)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 
Accumulate(Handle<String> new_part)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 
Extend()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 
Finish()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 
AppendString(Handle<String> string)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