LCOV - code coverage report
Current view: top level - src - string-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 107 127 84.3 %
Date: 2019-01-20 Functions: 20 24 83.3 %

          Line data    Source code
       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-inl.h"
       6             : 
       7             : #include "src/isolate-inl.h"
       8             : #include "src/objects/fixed-array-inl.h"
       9             : #include "src/objects/js-array-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : template <typename sinkchar>
      15        2234 : void StringBuilderConcatHelper(String special, sinkchar* sink,
      16             :                                FixedArray fixed_array, int array_length) {
      17             :   DisallowHeapAllocation no_gc;
      18             :   int position = 0;
      19      335499 :   for (int i = 0; i < array_length; i++) {
      20      333265 :     Object element = fixed_array->get(i);
      21      333265 :     if (element->IsSmi()) {
      22             :       // Smi encoding of position and length.
      23       61320 :       int encoded_slice = Smi::ToInt(element);
      24             :       int pos;
      25             :       int len;
      26       61320 :       if (encoded_slice > 0) {
      27             :         // Position and length encoded in one smi.
      28       61302 :         pos = StringBuilderSubstringPosition::decode(encoded_slice);
      29             :         len = StringBuilderSubstringLength::decode(encoded_slice);
      30             :       } else {
      31             :         // Position and length encoded in two smis.
      32          36 :         Object obj = fixed_array->get(++i);
      33             :         DCHECK(obj->IsSmi());
      34          18 :         pos = Smi::ToInt(obj);
      35          18 :         len = -encoded_slice;
      36             :       }
      37       61320 :       String::WriteToFlat(special, sink + position, pos, pos + len);
      38       61320 :       position += len;
      39             :     } else {
      40             :       String string = String::cast(element);
      41             :       int element_length = string->length();
      42      271945 :       String::WriteToFlat(string, sink + position, 0, element_length);
      43      271945 :       position += element_length;
      44             :     }
      45             :   }
      46        2234 : }
      47             : 
      48             : template void StringBuilderConcatHelper<uint8_t>(String special, uint8_t* sink,
      49             :                                                  FixedArray fixed_array,
      50             :                                                  int array_length);
      51             : 
      52             : template void StringBuilderConcatHelper<uc16>(String special, uc16* sink,
      53             :                                               FixedArray fixed_array,
      54             :                                               int array_length);
      55             : 
      56         659 : int StringBuilderConcatLength(int special_length, FixedArray fixed_array,
      57             :                               int array_length, bool* one_byte) {
      58             :   DisallowHeapAllocation no_gc;
      59             :   int position = 0;
      60      330459 :   for (int i = 0; i < array_length; i++) {
      61             :     int increment = 0;
      62      329809 :     Object elt = fixed_array->get(i);
      63      329809 :     if (elt->IsSmi()) {
      64             :       // Smi encoding of position and length.
      65       58737 :       int smi_value = Smi::ToInt(elt);
      66             :       int pos;
      67             :       int len;
      68       58737 :       if (smi_value > 0) {
      69             :         // Position and length encoded in one smi.
      70       58737 :         pos = StringBuilderSubstringPosition::decode(smi_value);
      71             :         len = StringBuilderSubstringLength::decode(smi_value);
      72             :       } else {
      73             :         // Position and length encoded in two smis.
      74           0 :         len = -smi_value;
      75             :         // Get the position and check that it is a positive smi.
      76           0 :         i++;
      77           0 :         if (i >= array_length) return -1;
      78           0 :         Object next_smi = fixed_array->get(i);
      79           0 :         if (!next_smi->IsSmi()) return -1;
      80           0 :         pos = Smi::ToInt(next_smi);
      81           0 :         if (pos < 0) return -1;
      82             :       }
      83             :       DCHECK_GE(pos, 0);
      84             :       DCHECK_GE(len, 0);
      85       58737 :       if (pos > special_length || len > special_length - pos) return -1;
      86             :       increment = len;
      87      271072 :     } else if (elt->IsString()) {
      88      271072 :       String element = String::cast(elt);
      89             :       int element_length = element->length();
      90             :       increment = element_length;
      91      271072 :       if (*one_byte && !element->HasOnlyOneByteChars()) {
      92           0 :         *one_byte = false;
      93             :       }
      94             :     } else {
      95             :       return -1;
      96             :     }
      97      329809 :     if (increment > String::kMaxLength - position) {
      98             :       return kMaxInt;  // Provoke throw on allocation.
      99             :     }
     100      329800 :     position += increment;
     101             :   }
     102             :   return position;
     103             : }
     104             : 
     105           0 : FixedArrayBuilder::FixedArrayBuilder(Isolate* isolate, int initial_capacity)
     106             :     : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
     107             :       length_(0),
     108        1620 :       has_non_smi_elements_(false) {
     109             :   // Require a non-zero initial size. Ensures that doubling the size to
     110             :   // extend the array will work.
     111             :   DCHECK_GT(initial_capacity, 0);
     112           0 : }
     113             : 
     114       93121 : FixedArrayBuilder::FixedArrayBuilder(Handle<FixedArray> backing_store)
     115       93121 :     : array_(backing_store), length_(0), has_non_smi_elements_(false) {
     116             :   // Require a non-zero initial size. Ensures that doubling the size to
     117             :   // extend the array will work.
     118             :   DCHECK_GT(backing_store->length(), 0);
     119       93121 : }
     120             : 
     121           0 : bool FixedArrayBuilder::HasCapacity(int elements) {
     122             :   int length = array_->length();
     123           0 :   int required_length = length_ + elements;
     124           0 :   return (length >= required_length);
     125             : }
     126             : 
     127      365893 : void FixedArrayBuilder::EnsureCapacity(Isolate* isolate, int elements) {
     128             :   int length = array_->length();
     129      365893 :   int required_length = length_ + elements;
     130      365893 :   if (length < required_length) {
     131             :     int new_length = length;
     132        1451 :     do {
     133        1451 :       new_length *= 2;
     134             :     } while (new_length < required_length);
     135             :     Handle<FixedArray> extended_array =
     136        1451 :         isolate->factory()->NewFixedArrayWithHoles(new_length);
     137        2902 :     array_->CopyTo(0, *extended_array, 0, length_);
     138        1451 :     array_ = extended_array;
     139             :   }
     140      365893 : }
     141             : 
     142      364633 : void FixedArrayBuilder::Add(Object value) {
     143             :   DCHECK(!value->IsSmi());
     144             :   DCHECK(length_ < capacity());
     145      729266 :   array_->set(length_, value);
     146      364633 :   length_++;
     147      364633 :   has_non_smi_elements_ = true;
     148      364633 : }
     149             : 
     150       61338 : void FixedArrayBuilder::Add(Smi value) {
     151             :   DCHECK(value->IsSmi());
     152             :   DCHECK(length_ < capacity());
     153       61338 :   array_->set(length_, value);
     154       61338 :   length_++;
     155       61338 : }
     156             : 
     157           0 : int FixedArrayBuilder::capacity() { return array_->length(); }
     158             : 
     159       93059 : Handle<JSArray> FixedArrayBuilder::ToJSArray(Handle<JSArray> target_array) {
     160       93059 :   JSArray::SetContent(target_array, array_);
     161      279177 :   target_array->set_length(Smi::FromInt(length_));
     162       93059 :   return target_array;
     163             : }
     164             : 
     165        1620 : ReplacementStringBuilder::ReplacementStringBuilder(Heap* heap,
     166             :                                                    Handle<String> subject,
     167             :                                                    int estimated_part_count)
     168             :     : heap_(heap),
     169             :       array_builder_(heap->isolate(), estimated_part_count),
     170             :       subject_(subject),
     171             :       character_count_(0),
     172        6480 :       is_one_byte_(subject->IsOneByteRepresentation()) {
     173             :   // Require a non-zero initial size. Ensures that doubling the size to
     174             :   // extend the array will work.
     175             :   DCHECK_GT(estimated_part_count, 0);
     176        1620 : }
     177             : 
     178        2421 : void ReplacementStringBuilder::EnsureCapacity(int elements) {
     179        4842 :   array_builder_.EnsureCapacity(heap_->isolate(), elements);
     180        2421 : }
     181             : 
     182        1161 : void ReplacementStringBuilder::AddString(Handle<String> string) {
     183             :   int length = string->length();
     184             :   DCHECK_GT(length, 0);
     185             :   AddElement(*string);
     186        1161 :   if (!string->IsOneByteRepresentation()) {
     187           0 :     is_one_byte_ = false;
     188             :   }
     189             :   IncrementCharacterCount(length);
     190        1161 : }
     191             : 
     192        1620 : MaybeHandle<String> ReplacementStringBuilder::ToString() {
     193        1620 :   Isolate* isolate = heap_->isolate();
     194        3204 :   if (array_builder_.length() == 0) {
     195          36 :     return isolate->factory()->empty_string();
     196             :   }
     197             : 
     198             :   Handle<String> joined_string;
     199        1584 :   if (is_one_byte_) {
     200             :     Handle<SeqOneByteString> seq;
     201        3168 :     ASSIGN_RETURN_ON_EXCEPTION(
     202             :         isolate, seq, isolate->factory()->NewRawOneByteString(character_count_),
     203             :         String);
     204             : 
     205             :     DisallowHeapAllocation no_gc;
     206             :     uint8_t* char_buffer = seq->GetChars(no_gc);
     207             :     StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
     208        1584 :                               array_builder_.length());
     209        1584 :     joined_string = Handle<String>::cast(seq);
     210             :   } else {
     211             :     // Two-byte.
     212             :     Handle<SeqTwoByteString> seq;
     213           0 :     ASSIGN_RETURN_ON_EXCEPTION(
     214             :         isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_),
     215             :         String);
     216             : 
     217             :     DisallowHeapAllocation no_gc;
     218             :     uc16* char_buffer = seq->GetChars(no_gc);
     219             :     StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
     220           0 :                               array_builder_.length());
     221           0 :     joined_string = Handle<String>::cast(seq);
     222             :   }
     223        1584 :   return joined_string;
     224             : }
     225             : 
     226           0 : void ReplacementStringBuilder::AddElement(Object element) {
     227             :   DCHECK(element->IsSmi() || element->IsString());
     228             :   DCHECK(array_builder_.capacity() > array_builder_.length());
     229        1161 :   array_builder_.Add(element);
     230           0 : }
     231             : 
     232    10932951 : IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate)
     233             :     : isolate_(isolate),
     234             :       encoding_(String::ONE_BYTE_ENCODING),
     235             :       overflowed_(false),
     236             :       part_length_(kInitialPartLength),
     237     5466475 :       current_index_(0) {
     238             :   // Create an accumulator handle starting with the empty string.
     239             :   accumulator_ =
     240     5466476 :       Handle<String>::New(ReadOnlyRoots(isolate).empty_string(), isolate);
     241             :   current_part_ =
     242    16399428 :       factory()->NewRawOneByteString(part_length_).ToHandleChecked();
     243     5466476 : }
     244             : 
     245     1088888 : int IncrementalStringBuilder::Length() const {
     246     1088888 :   return accumulator_->length() + current_index_;
     247             : }
     248             : 
     249    38174510 : void IncrementalStringBuilder::Accumulate(Handle<String> new_part) {
     250             :   Handle<String> new_accumulator;
     251    19087254 :   if (accumulator()->length() + new_part->length() > String::kMaxLength) {
     252             :     // Set the flag and carry on. Delay throwing the exception till the end.
     253             :     new_accumulator = factory()->empty_string();
     254          45 :     overflowed_ = true;
     255             :   } else {
     256             :     new_accumulator =
     257    38174419 :         factory()->NewConsString(accumulator(), new_part).ToHandleChecked();
     258             :   }
     259             :   set_accumulator(new_accumulator);
     260    19087255 : }
     261             : 
     262             : 
     263    15135440 : void IncrementalStringBuilder::Extend() {
     264             :   DCHECK_EQ(current_index_, current_part()->length());
     265     7567719 :   Accumulate(current_part());
     266     7567721 :   if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
     267     7413460 :     part_length_ *= kPartLengthGrowthFactor;
     268             :   }
     269             :   Handle<String> new_part;
     270     7567721 :   if (encoding_ == String::ONE_BYTE_ENCODING) {
     271    20545777 :     new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked();
     272             :   } else {
     273     2157384 :     new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked();
     274             :   }
     275             :   // Reuse the same handle to avoid being invalidated when exiting handle scope.
     276             :   set_current_part(new_part);
     277     7567720 :   current_index_ = 0;
     278     7567720 : }
     279             : 
     280             : 
     281     5465841 : MaybeHandle<String> IncrementalStringBuilder::Finish() {
     282     5465841 :   ShrinkCurrentPart();
     283     5465841 :   Accumulate(current_part());
     284     5465840 :   if (overflowed_) {
     285          45 :     THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String);
     286             :   }
     287     5465795 :   return accumulator();
     288             : }
     289             : 
     290             : 
     291     6053695 : void IncrementalStringBuilder::AppendString(Handle<String> string) {
     292     6053695 :   ShrinkCurrentPart();
     293     6053693 :   part_length_ = kInitialPartLength;  // Allocate conservatively.
     294     6053693 :   Extend();  // Attach current part and allocate new part.
     295     6053694 :   Accumulate(string);
     296     6053696 : }
     297             : }  // namespace internal
     298      183867 : }  // namespace v8

Generated by: LCOV version 1.10