PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/v8/src/string-builder.h

https://gitlab.com/CORP-RESELLER/node
C Header | 437 lines | 344 code | 70 blank | 23 comment | 51 complexity | 4cc1dba82f718963b1ed6f602930ed38 MD5 | raw 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. #ifndef V8_STRING_BUILDER_H_
  5. #define V8_STRING_BUILDER_H_
  6. #include "src/assert-scope.h"
  7. #include "src/factory.h"
  8. #include "src/handles.h"
  9. #include "src/isolate.h"
  10. #include "src/objects.h"
  11. #include "src/utils.h"
  12. namespace v8 {
  13. namespace internal {
  14. const int kStringBuilderConcatHelperLengthBits = 11;
  15. const int kStringBuilderConcatHelperPositionBits = 19;
  16. typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
  17. StringBuilderSubstringLength;
  18. typedef BitField<int, kStringBuilderConcatHelperLengthBits,
  19. kStringBuilderConcatHelperPositionBits>
  20. StringBuilderSubstringPosition;
  21. template <typename sinkchar>
  22. static inline void StringBuilderConcatHelper(String* special, sinkchar* sink,
  23. FixedArray* fixed_array,
  24. int array_length) {
  25. DisallowHeapAllocation no_gc;
  26. int position = 0;
  27. for (int i = 0; i < array_length; i++) {
  28. Object* element = fixed_array->get(i);
  29. if (element->IsSmi()) {
  30. // Smi encoding of position and length.
  31. int encoded_slice = Smi::cast(element)->value();
  32. int pos;
  33. int len;
  34. if (encoded_slice > 0) {
  35. // Position and length encoded in one smi.
  36. pos = StringBuilderSubstringPosition::decode(encoded_slice);
  37. len = StringBuilderSubstringLength::decode(encoded_slice);
  38. } else {
  39. // Position and length encoded in two smis.
  40. Object* obj = fixed_array->get(++i);
  41. DCHECK(obj->IsSmi());
  42. pos = Smi::cast(obj)->value();
  43. len = -encoded_slice;
  44. }
  45. String::WriteToFlat(special, sink + position, pos, pos + len);
  46. position += len;
  47. } else {
  48. String* string = String::cast(element);
  49. int element_length = string->length();
  50. String::WriteToFlat(string, sink + position, 0, element_length);
  51. position += element_length;
  52. }
  53. }
  54. }
  55. // Returns the result length of the concatenation.
  56. // On illegal argument, -1 is returned.
  57. static inline int StringBuilderConcatLength(int special_length,
  58. FixedArray* fixed_array,
  59. int array_length, bool* one_byte) {
  60. DisallowHeapAllocation no_gc;
  61. int position = 0;
  62. for (int i = 0; i < array_length; i++) {
  63. int increment = 0;
  64. Object* elt = fixed_array->get(i);
  65. if (elt->IsSmi()) {
  66. // Smi encoding of position and length.
  67. int smi_value = Smi::cast(elt)->value();
  68. int pos;
  69. int len;
  70. if (smi_value > 0) {
  71. // Position and length encoded in one smi.
  72. pos = StringBuilderSubstringPosition::decode(smi_value);
  73. len = StringBuilderSubstringLength::decode(smi_value);
  74. } else {
  75. // Position and length encoded in two smis.
  76. len = -smi_value;
  77. // Get the position and check that it is a positive smi.
  78. i++;
  79. if (i >= array_length) return -1;
  80. Object* next_smi = fixed_array->get(i);
  81. if (!next_smi->IsSmi()) return -1;
  82. pos = Smi::cast(next_smi)->value();
  83. if (pos < 0) return -1;
  84. }
  85. DCHECK(pos >= 0);
  86. DCHECK(len >= 0);
  87. if (pos > special_length || len > special_length - pos) return -1;
  88. increment = len;
  89. } else if (elt->IsString()) {
  90. String* element = String::cast(elt);
  91. int element_length = element->length();
  92. increment = element_length;
  93. if (*one_byte && !element->HasOnlyOneByteChars()) {
  94. *one_byte = false;
  95. }
  96. } else {
  97. return -1;
  98. }
  99. if (increment > String::kMaxLength - position) {
  100. return kMaxInt; // Provoke throw on allocation.
  101. }
  102. position += increment;
  103. }
  104. return position;
  105. }
  106. class FixedArrayBuilder {
  107. public:
  108. explicit 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(initial_capacity > 0);
  115. }
  116. explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
  117. : array_(backing_store), length_(0), has_non_smi_elements_(false) {
  118. // Require a non-zero initial size. Ensures that doubling the size to
  119. // extend the array will work.
  120. DCHECK(backing_store->length() > 0);
  121. }
  122. bool HasCapacity(int elements) {
  123. int length = array_->length();
  124. int required_length = length_ + elements;
  125. return (length >= required_length);
  126. }
  127. void EnsureCapacity(int elements) {
  128. int length = array_->length();
  129. int required_length = length_ + elements;
  130. if (length < required_length) {
  131. int new_length = length;
  132. do {
  133. new_length *= 2;
  134. } while (new_length < required_length);
  135. Handle<FixedArray> extended_array =
  136. array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
  137. array_->CopyTo(0, *extended_array, 0, length_);
  138. array_ = extended_array;
  139. }
  140. }
  141. void Add(Object* value) {
  142. DCHECK(!value->IsSmi());
  143. DCHECK(length_ < capacity());
  144. array_->set(length_, value);
  145. length_++;
  146. has_non_smi_elements_ = true;
  147. }
  148. void Add(Smi* value) {
  149. DCHECK(value->IsSmi());
  150. DCHECK(length_ < capacity());
  151. array_->set(length_, value);
  152. length_++;
  153. }
  154. Handle<FixedArray> array() { return array_; }
  155. int length() { return length_; }
  156. int capacity() { return array_->length(); }
  157. Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
  158. JSArray::SetContent(target_array, array_);
  159. target_array->set_length(Smi::FromInt(length_));
  160. return target_array;
  161. }
  162. private:
  163. Handle<FixedArray> array_;
  164. int length_;
  165. bool has_non_smi_elements_;
  166. };
  167. class ReplacementStringBuilder {
  168. public:
  169. ReplacementStringBuilder(Heap* heap, Handle<String> subject,
  170. int estimated_part_count)
  171. : heap_(heap),
  172. array_builder_(heap->isolate(), estimated_part_count),
  173. subject_(subject),
  174. character_count_(0),
  175. is_one_byte_(subject->IsOneByteRepresentation()) {
  176. // Require a non-zero initial size. Ensures that doubling the size to
  177. // extend the array will work.
  178. DCHECK(estimated_part_count > 0);
  179. }
  180. static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from,
  181. int to) {
  182. DCHECK(from >= 0);
  183. int length = to - from;
  184. DCHECK(length > 0);
  185. if (StringBuilderSubstringLength::is_valid(length) &&
  186. StringBuilderSubstringPosition::is_valid(from)) {
  187. int encoded_slice = StringBuilderSubstringLength::encode(length) |
  188. StringBuilderSubstringPosition::encode(from);
  189. builder->Add(Smi::FromInt(encoded_slice));
  190. } else {
  191. // Otherwise encode as two smis.
  192. builder->Add(Smi::FromInt(-length));
  193. builder->Add(Smi::FromInt(from));
  194. }
  195. }
  196. void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); }
  197. void AddSubjectSlice(int from, int to) {
  198. AddSubjectSlice(&array_builder_, from, to);
  199. IncrementCharacterCount(to - from);
  200. }
  201. void AddString(Handle<String> string) {
  202. int length = string->length();
  203. DCHECK(length > 0);
  204. AddElement(*string);
  205. if (!string->IsOneByteRepresentation()) {
  206. is_one_byte_ = false;
  207. }
  208. IncrementCharacterCount(length);
  209. }
  210. MaybeHandle<String> ToString();
  211. void IncrementCharacterCount(int by) {
  212. if (character_count_ > String::kMaxLength - by) {
  213. STATIC_ASSERT(String::kMaxLength < kMaxInt);
  214. character_count_ = kMaxInt;
  215. } else {
  216. character_count_ += by;
  217. }
  218. }
  219. private:
  220. void AddElement(Object* element) {
  221. DCHECK(element->IsSmi() || element->IsString());
  222. DCHECK(array_builder_.capacity() > array_builder_.length());
  223. array_builder_.Add(element);
  224. }
  225. Heap* heap_;
  226. FixedArrayBuilder array_builder_;
  227. Handle<String> subject_;
  228. int character_count_;
  229. bool is_one_byte_;
  230. };
  231. class IncrementalStringBuilder {
  232. public:
  233. explicit IncrementalStringBuilder(Isolate* isolate);
  234. INLINE(String::Encoding CurrentEncoding()) { return encoding_; }
  235. template <typename SrcChar, typename DestChar>
  236. INLINE(void Append(SrcChar c));
  237. INLINE(void AppendCharacter(uint8_t c)) {
  238. if (encoding_ == String::ONE_BYTE_ENCODING) {
  239. Append<uint8_t, uint8_t>(c);
  240. } else {
  241. Append<uint8_t, uc16>(c);
  242. }
  243. }
  244. INLINE(void AppendCString(const char* s)) {
  245. const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
  246. if (encoding_ == String::ONE_BYTE_ENCODING) {
  247. while (*u != '\0') Append<uint8_t, uint8_t>(*(u++));
  248. } else {
  249. while (*u != '\0') Append<uint8_t, uc16>(*(u++));
  250. }
  251. }
  252. INLINE(bool CurrentPartCanFit(int length)) {
  253. return part_length_ - current_index_ > length;
  254. }
  255. void AppendString(Handle<String> string);
  256. MaybeHandle<String> Finish();
  257. // Change encoding to two-byte.
  258. void ChangeEncoding() {
  259. DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
  260. ShrinkCurrentPart();
  261. encoding_ = String::TWO_BYTE_ENCODING;
  262. Extend();
  263. }
  264. template <typename DestChar>
  265. class NoExtend {
  266. public:
  267. explicit NoExtend(Handle<String> string, int offset) {
  268. DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString());
  269. if (sizeof(DestChar) == 1) {
  270. start_ = reinterpret_cast<DestChar*>(
  271. Handle<SeqOneByteString>::cast(string)->GetChars() + offset);
  272. } else {
  273. start_ = reinterpret_cast<DestChar*>(
  274. Handle<SeqTwoByteString>::cast(string)->GetChars() + offset);
  275. }
  276. cursor_ = start_;
  277. }
  278. INLINE(void Append(DestChar c)) { *(cursor_++) = c; }
  279. INLINE(void AppendCString(const char* s)) {
  280. const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
  281. while (*u != '\0') Append(*(u++));
  282. }
  283. int written() { return static_cast<int>(cursor_ - start_); }
  284. private:
  285. DestChar* start_;
  286. DestChar* cursor_;
  287. DisallowHeapAllocation no_gc_;
  288. };
  289. template <typename DestChar>
  290. class NoExtendString : public NoExtend<DestChar> {
  291. public:
  292. NoExtendString(Handle<String> string, int required_length)
  293. : NoExtend<DestChar>(string, 0), string_(string) {
  294. DCHECK(string->length() >= required_length);
  295. }
  296. Handle<String> Finalize() {
  297. Handle<SeqString> string = Handle<SeqString>::cast(string_);
  298. int length = NoExtend<DestChar>::written();
  299. Handle<String> result = SeqString::Truncate(string, length);
  300. string_ = Handle<String>();
  301. return result;
  302. }
  303. private:
  304. Handle<String> string_;
  305. };
  306. template <typename DestChar>
  307. class NoExtendBuilder : public NoExtend<DestChar> {
  308. public:
  309. NoExtendBuilder(IncrementalStringBuilder* builder, int required_length)
  310. : NoExtend<DestChar>(builder->current_part(), builder->current_index_),
  311. builder_(builder) {
  312. DCHECK(builder->CurrentPartCanFit(required_length));
  313. }
  314. ~NoExtendBuilder() {
  315. builder_->current_index_ += NoExtend<DestChar>::written();
  316. }
  317. private:
  318. IncrementalStringBuilder* builder_;
  319. };
  320. private:
  321. Factory* factory() { return isolate_->factory(); }
  322. INLINE(Handle<String> accumulator()) { return accumulator_; }
  323. INLINE(void set_accumulator(Handle<String> string)) {
  324. *accumulator_.location() = *string;
  325. }
  326. INLINE(Handle<String> current_part()) { return current_part_; }
  327. INLINE(void set_current_part(Handle<String> string)) {
  328. *current_part_.location() = *string;
  329. }
  330. // Add the current part to the accumulator.
  331. void Accumulate(Handle<String> new_part);
  332. // Finish the current part and allocate a new part.
  333. void Extend();
  334. // Shrink current part to the right size.
  335. void ShrinkCurrentPart() {
  336. DCHECK(current_index_ < part_length_);
  337. set_current_part(SeqString::Truncate(
  338. Handle<SeqString>::cast(current_part()), current_index_));
  339. }
  340. static const int kInitialPartLength = 32;
  341. static const int kMaxPartLength = 16 * 1024;
  342. static const int kPartLengthGrowthFactor = 2;
  343. Isolate* isolate_;
  344. String::Encoding encoding_;
  345. bool overflowed_;
  346. int part_length_;
  347. int current_index_;
  348. Handle<String> accumulator_;
  349. Handle<String> current_part_;
  350. };
  351. template <typename SrcChar, typename DestChar>
  352. void IncrementalStringBuilder::Append(SrcChar c) {
  353. DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1);
  354. if (sizeof(DestChar) == 1) {
  355. DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
  356. SeqOneByteString::cast(*current_part_)
  357. ->SeqOneByteStringSet(current_index_++, c);
  358. } else {
  359. DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_);
  360. SeqTwoByteString::cast(*current_part_)
  361. ->SeqTwoByteStringSet(current_index_++, c);
  362. }
  363. if (current_index_ == part_length_) Extend();
  364. }
  365. } // namespace internal
  366. } // namespace v8
  367. #endif // V8_STRING_BUILDER_H_