v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-builder.cc
Go to the documentation of this file.
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/base/strings.h"
10
11namespace v8 {
12namespace internal {
13
14template <typename sinkchar>
15void StringBuilderConcatHelper(Tagged<String> special, sinkchar* sink,
16 Tagged<FixedArray> fixed_array,
17 int array_length) {
19 int position = 0;
20 for (int i = 0; i < array_length; i++) {
21 Tagged<Object> element = fixed_array->get(i);
22 if (IsSmi(element)) {
23 // Smi encoding of position and length.
24 int encoded_slice = Smi::ToInt(element);
25 int pos;
26 int len;
27 if (encoded_slice > 0) {
28 // Position and length encoded in one smi.
30 len = StringBuilderSubstringLength::decode(encoded_slice);
31 } else {
32 // Position and length encoded in two smis.
33 Tagged<Object> obj = fixed_array->get(++i);
34 DCHECK(IsSmi(obj));
35 pos = Smi::ToInt(obj);
36 len = -encoded_slice;
37 }
38 String::WriteToFlat(special, sink + position, pos, len);
39 position += len;
40 } else {
41 Tagged<String> string = Cast<String>(element);
42 int element_length = string->length();
43 String::WriteToFlat(string, sink + position, 0, element_length);
44 position += element_length;
45 }
46 }
47}
48
50 uint8_t* sink,
51 Tagged<FixedArray> fixed_array,
52 int array_length);
53
55 Tagged<String> special, base::uc16* sink, Tagged<FixedArray> fixed_array,
56 int array_length);
57
58int StringBuilderConcatLength(int special_length,
59 Tagged<FixedArray> fixed_array, int array_length,
60 bool* one_byte) {
62 int position = 0;
63 for (int i = 0; i < array_length; i++) {
64 uint32_t increment = 0;
65 Tagged<Object> elt = fixed_array->get(i);
66 if (IsSmi(elt)) {
67 // Smi encoding of position and length.
68 int smi_value = Smi::ToInt(elt);
69 int pos;
70 int len;
71 if (smi_value > 0) {
72 // Position and length encoded in one smi.
75 } else {
76 // Position and length encoded in two smis.
77 len = -smi_value;
78 // Get the position and check that it is a positive smi.
79 i++;
80 if (i >= array_length) return -1;
81 Tagged<Object> next_smi = fixed_array->get(i);
82 if (!IsSmi(next_smi)) return -1;
83 pos = Smi::ToInt(next_smi);
84 if (pos < 0) return -1;
85 }
86 DCHECK_GE(pos, 0);
87 DCHECK_GE(len, 0);
88 if (pos > special_length || len > special_length - pos) return -1;
89 increment = len;
90 } else if (IsString(elt)) {
91 Tagged<String> element = Cast<String>(elt);
92 int element_length = element->length();
93 increment = element_length;
94 if (*one_byte && !element->IsOneByteRepresentation()) {
95 *one_byte = false;
96 }
97 } else {
98 return -1;
99 }
101 return kMaxInt; // Provoke throw on allocation.
102 }
104 }
105 return position;
106}
107
108FixedArrayBuilder::FixedArrayBuilder(Isolate* isolate, int initial_capacity)
109 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
110 length_(0),
111 has_non_smi_elements_(false) {
112 // Require a non-zero initial size. Ensures that doubling the size to
113 // extend the array will work.
114 DCHECK_GT(initial_capacity, 0);
115}
116
118 : array_(backing_store), length_(0), has_non_smi_elements_(false) {
119 // Require a non-zero initial size. Ensures that doubling the size to
120 // extend the array will work.
121 DCHECK_GT(backing_store->length(), 0);
122}
123
125 : array_(isolate->factory()->empty_fixed_array()),
126 length_(0),
127 has_non_smi_elements_(false) {}
128
129// static
133
135 int length = array_->length();
136 int required_length = length_ + elements;
137 return (length >= required_length);
138}
139
140void FixedArrayBuilder::EnsureCapacity(Isolate* isolate, int elements) {
141 int length = array_->length();
142 int required_length = length_ + elements;
143 if (length < required_length) {
144 if (length == 0) {
145 constexpr int kInitialCapacityForLazy = 16;
146 array_ = isolate->factory()->NewFixedArrayWithHoles(
147 std::max(kInitialCapacityForLazy, elements));
148 return;
149 }
150
151 int new_length = length;
152 do {
153 new_length *= 2;
154 } while (new_length < required_length);
155 DirectHandle<FixedArray> extended_array =
156 isolate->factory()->NewFixedArrayWithHoles(new_length);
157 FixedArray::CopyElements(isolate, *extended_array, 0, *array_, 0, length_);
158 array_ = extended_array;
159 }
160}
161
163 DCHECK(!IsSmi(value));
164 array_->set(length_, value);
165 length_++;
167}
168
170 DCHECK(IsSmi(value));
171 array_->set(length_, value);
172 length_++;
173}
174
175int FixedArrayBuilder::capacity() { return array_->length(); }
176
178 DirectHandle<String> subject,
179 int estimated_part_count)
180 : heap_(heap),
181 array_builder_(Isolate::FromHeap(heap), estimated_part_count),
182 subject_(subject),
183 character_count_(0),
184 is_one_byte_(subject->IsOneByteRepresentation()) {
185 // Require a non-zero initial size. Ensures that doubling the size to
186 // extend the array will work.
187 DCHECK_GT(estimated_part_count, 0);
188}
189
193
195 uint32_t length = string->length();
196 AddElement(string);
197 if (!string->IsOneByteRepresentation()) {
198 is_one_byte_ = false;
199 }
201}
202
204 Isolate* isolate = Isolate::FromHeap(heap_);
205 if (array_builder_.length() == 0) {
206 return isolate->factory()->empty_string();
207 }
208
209 DirectHandle<String> joined_string;
210 if (is_one_byte_) {
213 isolate, seq,
214 isolate->factory()->NewRawOneByteString(character_count_));
215
217 uint8_t* char_buffer = seq->GetChars(no_gc);
220 joined_string = Cast<String>(seq);
221 } else {
222 // Two-byte.
225 isolate, seq,
226 isolate->factory()->NewRawTwoByteString(character_count_));
227
229 base::uc16* char_buffer = seq->GetChars(no_gc);
232 joined_string = Cast<String>(seq);
233 }
234 return joined_string;
235}
236
238 DCHECK(IsSmi(*element) || IsString(*element));
241 array_builder_.Add(*element);
242}
243
245 : isolate_(isolate),
246 encoding_(String::ONE_BYTE_ENCODING),
247 overflowed_(false),
248 part_length_(kInitialPartLength),
249 current_index_(0) {
250 // Create an accumulator handle starting with the empty string.
252 DirectHandle<String>::New(ReadOnlyRoots(isolate).empty_string(), isolate);
254 factory()->NewRawOneByteString(part_length_).ToHandleChecked();
255}
256
258 return accumulator_->length() + current_index_;
259}
260
264
266 DirectHandle<String> new_accumulator;
267 if (accumulator()->length() + new_part->length() > String::kMaxLength) {
268 // Set the flag and carry on. Delay throwing the exception till the end.
269 new_accumulator = factory()->empty_string();
270 overflowed_ = true;
271 } else {
272 new_accumulator =
273 factory()
275 indirect_handle(new_part, isolate_))
276 .ToHandleChecked();
277 }
278 set_accumulator(new_accumulator);
279}
280
286 }
287 DirectHandle<String> new_part;
289 new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked();
290 } else {
291 new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked();
292 }
293 // Reuse the same handle to avoid being invalidated when exiting handle scope.
294 set_current_part(new_part);
295 current_index_ = 0;
296}
297
301 if (overflowed_) {
302 THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError());
303 }
304 if (isolate()->serializer_enabled()) {
305 return factory()->InternalizeString(
307 }
308 return accumulator();
309}
310
311// Short strings can be copied directly to {current_part_}.
312// Requires the IncrementalStringBuilder to either have two byte encoding or
313// the incoming string to have one byte representation "underneath" (The
314// one byte check requires the string to be flat).
316 const bool representation_ok =
318 (string->IsFlat() && String::IsOneByteRepresentationUnderneath(*string));
319
320 return representation_ok && CurrentPartCanFit(string->length());
321}
322
324 DCHECK(CanAppendByCopy(string));
325
326 {
330 *string,
331 Cast<SeqOneByteString>(current_part())->GetChars(no_gc) +
333 0, string->length());
334 } else {
336 *string,
337 Cast<SeqTwoByteString>(current_part())->GetChars(no_gc) +
339 0, string->length());
340 }
341 }
342 current_index_ += string->length();
345}
346
348 if (CanAppendByCopy(string)) {
349 AppendStringByCopy(string);
350 return;
351 }
352
354 part_length_ = kInitialPartLength; // Allocate conservatively.
355 Extend(); // Attach current part and allocate new part.
356 Accumulate(string);
357}
358
359} // namespace internal
360} // namespace v8
Isolate * isolate_
SourcePosition pos
static constexpr T decode(U value)
Definition bit-field.h:66
static V8_INLINE DirectHandle< T > New(Tagged< T > object, Isolate *isolate)
Definition handles.h:664
V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType NewConsString(HandleType< String > left, HandleType< String > right, AllocationType allocation=AllocationType::kYoung)
V8_WARN_UNUSED_RESULT MaybeHandle< SeqOneByteString > NewRawOneByteString(int length, AllocationType allocation=AllocationType::kYoung)
V8_WARN_UNUSED_RESULT MaybeHandle< SeqTwoByteString > NewRawTwoByteString(int length, AllocationType allocation=AllocationType::kYoung)
Handle< String > InternalizeString(base::Vector< const char > str, bool convert_encoding=false)
Definition factory.h:216
void Add(Tagged< Object > value)
void EnsureCapacity(Isolate *isolate, int elements)
FixedArrayBuilder(Isolate *isolate, int initial_capacity)
DirectHandle< FixedArray > array()
DirectHandle< FixedArray > array_
static FixedArrayBuilder Lazy(Isolate *isolate)
void CopyElements(Isolate *isolate, int dst_index, Tagged< FixedArray > src, int src_index, int len, WriteBarrierMode mode)
void Accumulate(DirectHandle< String > new_part)
bool CanAppendByCopy(DirectHandle< String > string)
V8_INLINE DirectHandle< String > accumulator()
V8_INLINE DirectHandle< String > current_part()
V8_INLINE void set_current_part(DirectHandle< String > string)
void AppendStringByCopy(DirectHandle< String > string)
MaybeDirectHandle< String > Finish()
V8_INLINE void AppendString(std::string_view str)
V8_INLINE void set_accumulator(DirectHandle< String > string)
V8_INLINE bool CurrentPartCanFit(int length)
static Isolate * FromHeap(const Heap *heap)
Definition isolate.h:1202
ReplacementStringBuilder(Heap *heap, DirectHandle< String > subject, int estimated_part_count)
MaybeDirectHandle< String > ToString()
void AddString(DirectHandle< String > string)
void AddElement(DirectHandle< Object > element)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
Definition string.cc:772
static const uint32_t kMaxLength
Definition string.h:511
static bool IsOneByteRepresentationUnderneath(Tagged< String > string)
Definition string-inl.h:373
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
double increment
int position
Definition liveedit.cc:290
const int length_
Definition mul-fft.cc:473
uint16_t uc16
Definition strings.h:18
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
void StringBuilderConcatHelper(Tagged< String > special, sinkchar *sink, Tagged< FixedArray > fixed_array, int array_length)
int StringBuilderConcatLength(int special_length, Tagged< FixedArray > fixed_array, int array_length, bool *one_byte)
constexpr int kMaxInt
Definition globals.h:374
template void StringBuilderConcatHelper< uint8_t >(Tagged< String > special, uint8_t *sink, Tagged< FixedArray > fixed_array, int array_length)
template void StringBuilderConcatHelper< base::uc16 >(Tagged< String > special, base::uc16 *sink, Tagged< FixedArray > fixed_array, int array_length)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
DirectHandle< String > subject_
base::Vector< const DirectHandle< Object > > array_
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
Heap * heap_