// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/string-builder.h" #include "src/isolate-inl.h" #include "src/objects-inl.h" namespace v8 { namespace internal { MaybeHandle ReplacementStringBuilder::ToString() { Isolate* isolate = heap_->isolate(); if (array_builder_.length() == 0) { return isolate->factory()->empty_string(); } Handle joined_string; if (is_one_byte_) { Handle seq; ASSIGN_RETURN_ON_EXCEPTION( isolate, seq, isolate->factory()->NewRawOneByteString(character_count_), String); DisallowHeapAllocation no_gc; uint8_t* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), array_builder_.length()); joined_string = Handle::cast(seq); } else { // Two-byte. Handle seq; ASSIGN_RETURN_ON_EXCEPTION( isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_), String); DisallowHeapAllocation no_gc; uc16* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), array_builder_.length()); joined_string = Handle::cast(seq); } return joined_string; } IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate) : isolate_(isolate), encoding_(String::ONE_BYTE_ENCODING), overflowed_(false), part_length_(kInitialPartLength), current_index_(0) { // Create an accumulator handle starting with the empty string. accumulator_ = Handle::New(isolate->heap()->empty_string(), isolate); current_part_ = factory()->NewRawOneByteString(part_length_).ToHandleChecked(); } void IncrementalStringBuilder::Accumulate(Handle new_part) { Handle new_accumulator; if (accumulator()->length() + new_part->length() > String::kMaxLength) { // Set the flag and carry on. Delay throwing the exception till the end. new_accumulator = factory()->empty_string(); overflowed_ = true; } else { new_accumulator = factory()->NewConsString(accumulator(), new_part).ToHandleChecked(); } set_accumulator(new_accumulator); } void IncrementalStringBuilder::Extend() { DCHECK_EQ(current_index_, current_part()->length()); Accumulate(current_part()); if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { part_length_ *= kPartLengthGrowthFactor; } Handle new_part; if (encoding_ == String::ONE_BYTE_ENCODING) { new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked(); } else { new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked(); } // Reuse the same handle to avoid being invalidated when exiting handle scope. set_current_part(new_part); current_index_ = 0; } MaybeHandle IncrementalStringBuilder::Finish() { ShrinkCurrentPart(); Accumulate(current_part()); if (overflowed_) { THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String); } return accumulator(); } void IncrementalStringBuilder::AppendString(Handle string) { ShrinkCurrentPart(); part_length_ = kInitialPartLength; // Allocate conservatively. Extend(); // Attach current part and allocate new part. Accumulate(string); } } // namespace internal } // namespace v8