Home | History | Annotate | Download | only in src
      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