Coverage Report

Created: 2025-06-24 06:43

/src/hermes/lib/VM/StringPrimitive.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#include "hermes/VM/StringPrimitive.h"
9
10
#include "hermes/Support/Algorithms.h"
11
#include "hermes/Support/UTF8.h"
12
#include "hermes/VM/BuildMetadata.h"
13
#include "hermes/VM/FillerCell.h"
14
#include "hermes/VM/GCPointer-inline.h"
15
#include "hermes/VM/HermesValue-inline.h"
16
#include "hermes/VM/StringBuilder.h"
17
#include "hermes/VM/StringView.h"
18
#include "llvh/Support/ConvertUTF.h"
19
#pragma GCC diagnostic push
20
21
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
22
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
23
#endif
24
namespace hermes {
25
namespace vm {
26
27
void DynamicASCIIStringPrimitiveBuildMeta(
28
    const GCCell *cell,
29
1
    Metadata::Builder &mb) {
30
1
  mb.setVTable(&DynamicASCIIStringPrimitive::vt);
31
1
}
32
void DynamicUTF16StringPrimitiveBuildMeta(
33
    const GCCell *cell,
34
1
    Metadata::Builder &mb) {
35
1
  mb.setVTable(&DynamicUTF16StringPrimitive::vt);
36
1
}
37
38
void DynamicUniquedASCIIStringPrimitiveBuildMeta(
39
    const GCCell *cell,
40
1
    Metadata::Builder &mb) {
41
1
  mb.setVTable(&DynamicUniquedASCIIStringPrimitive::vt);
42
1
}
43
44
void DynamicUniquedUTF16StringPrimitiveBuildMeta(
45
    const GCCell *cell,
46
1
    Metadata::Builder &mb) {
47
1
  mb.setVTable(&DynamicUniquedUTF16StringPrimitive::vt);
48
1
}
49
50
void ExternalASCIIStringPrimitiveBuildMeta(
51
    const GCCell *cell,
52
1
    Metadata::Builder &mb) {
53
1
  mb.setVTable(&ExternalASCIIStringPrimitive::vt);
54
1
}
55
56
void ExternalUTF16StringPrimitiveBuildMeta(
57
    const GCCell *cell,
58
1
    Metadata::Builder &mb) {
59
1
  mb.setVTable(&ExternalUTF16StringPrimitive::vt);
60
1
}
61
62
template <typename T>
63
CallResult<HermesValue> StringPrimitive::createEfficientImpl(
64
    Runtime &runtime,
65
    llvh::ArrayRef<T> str,
66
257k
    std::basic_string<T> *optStorage) {
67
257k
  constexpr bool charIs8Bit = std::is_same<T, char>::value;
68
257k
  assert(
69
257k
      (!optStorage ||
70
257k
       str == llvh::makeArrayRef(optStorage->data(), optStorage->size())) &&
71
257k
      "If optStorage is provided, it must equal the input string");
72
257k
  assert(
73
257k
      (!charIs8Bit || isAllASCII(str.begin(), str.end())) &&
74
257k
      "8 bit strings must be ASCII");
75
257k
  if (str.empty()) {
76
0
    return HermesValue::encodeStringValue(
77
0
        runtime.getPredefinedString(Predefined::emptyString));
78
0
  }
79
257k
  if (str.size() == 1) {
80
53
    return runtime.getCharacterString(str[0]).getHermesValue();
81
53
  }
82
83
  // Check if we should acquire ownership of storage.
84
257k
  if (optStorage != nullptr &&
85
257k
      str.size() >= StringPrimitive::EXTERNAL_STRING_MIN_SIZE) {
86
0
    return ExternalStringPrimitive<T>::create(runtime, std::move(*optStorage));
87
0
  }
88
89
  // Check if we fit in ASCII.
90
  // We are ASCII if we are 8 bit, or we are 16 bit and all of our text is
91
  // ASCII.
92
257k
  bool isAscii = charIs8Bit || isAllASCII(str.begin(), str.end());
93
257k
  if (isAscii) {
94
257k
    auto result = StringPrimitive::create(runtime, str.size(), isAscii);
95
257k
    if (LLVM_UNLIKELY(result == ExecutionStatus::EXCEPTION)) {
96
0
      return ExecutionStatus::EXCEPTION;
97
0
    }
98
257k
    auto output = runtime.makeHandle<StringPrimitive>(*result);
99
    // Copy directly into the StringPrimitive storage.
100
#ifdef _MSC_VER
101
#pragma warning(push)
102
#pragma warning(disable : 4244)
103
#endif
104
105
257k
    std::copy(str.begin(), str.end(), output->castToASCIIPointerForWrite());
106
#ifdef _MSC_VER
107
#pragma warning(pop)
108
#endif
109
257k
    return output.getHermesValue();
110
257k
  }
111
112
0
  return StringPrimitive::create(runtime, str);
113
257k
}
hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::StringPrimitive::createEfficientImpl<char>(hermes::vm::Runtime&, llvh::ArrayRef<char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
66
257k
    std::basic_string<T> *optStorage) {
67
257k
  constexpr bool charIs8Bit = std::is_same<T, char>::value;
68
257k
  assert(
69
257k
      (!optStorage ||
70
257k
       str == llvh::makeArrayRef(optStorage->data(), optStorage->size())) &&
71
257k
      "If optStorage is provided, it must equal the input string");
72
257k
  assert(
73
257k
      (!charIs8Bit || isAllASCII(str.begin(), str.end())) &&
74
257k
      "8 bit strings must be ASCII");
75
257k
  if (str.empty()) {
76
0
    return HermesValue::encodeStringValue(
77
0
        runtime.getPredefinedString(Predefined::emptyString));
78
0
  }
79
257k
  if (str.size() == 1) {
80
53
    return runtime.getCharacterString(str[0]).getHermesValue();
81
53
  }
82
83
  // Check if we should acquire ownership of storage.
84
257k
  if (optStorage != nullptr &&
85
257k
      str.size() >= StringPrimitive::EXTERNAL_STRING_MIN_SIZE) {
86
0
    return ExternalStringPrimitive<T>::create(runtime, std::move(*optStorage));
87
0
  }
88
89
  // Check if we fit in ASCII.
90
  // We are ASCII if we are 8 bit, or we are 16 bit and all of our text is
91
  // ASCII.
92
257k
  bool isAscii = charIs8Bit || isAllASCII(str.begin(), str.end());
93
257k
  if (isAscii) {
94
257k
    auto result = StringPrimitive::create(runtime, str.size(), isAscii);
95
257k
    if (LLVM_UNLIKELY(result == ExecutionStatus::EXCEPTION)) {
96
0
      return ExecutionStatus::EXCEPTION;
97
0
    }
98
257k
    auto output = runtime.makeHandle<StringPrimitive>(*result);
99
    // Copy directly into the StringPrimitive storage.
100
#ifdef _MSC_VER
101
#pragma warning(push)
102
#pragma warning(disable : 4244)
103
#endif
104
105
257k
    std::copy(str.begin(), str.end(), output->castToASCIIPointerForWrite());
106
#ifdef _MSC_VER
107
#pragma warning(pop)
108
#endif
109
257k
    return output.getHermesValue();
110
257k
  }
111
112
0
  return StringPrimitive::create(runtime, str);
113
257k
}
Unexecuted instantiation: hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::StringPrimitive::createEfficientImpl<char16_t>(hermes::vm::Runtime&, llvh::ArrayRef<char16_t>, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >*)
114
115
CallResult<HermesValue> StringPrimitive::createEfficient(
116
    Runtime &runtime,
117
257k
    ASCIIRef str) {
118
257k
  return createEfficientImpl(runtime, str);
119
257k
}
120
121
static ExecutionStatus convertUtf8ToUtf16(
122
    Runtime &runtime,
123
    UTF8Ref utf8,
124
    bool IgnoreInputErrors,
125
0
    std::u16string &out) {
126
0
  out.resize(utf8.size());
127
0
  const llvh::UTF8 *sourceStart = (const llvh::UTF8 *)utf8.data();
128
0
  const llvh::UTF8 *sourceEnd = sourceStart + utf8.size();
129
0
  llvh::UTF16 *targetStart = (llvh::UTF16 *)&out[0];
130
0
  llvh::UTF16 *targetEnd = targetStart + out.size();
131
0
  llvh::ConversionResult cRes = llvh::ConvertUTF8toUTF16(
132
0
      &sourceStart,
133
0
      sourceEnd,
134
0
      &targetStart,
135
0
      targetEnd,
136
0
      llvh::lenientConversion);
137
0
  switch (cRes) {
138
0
    case llvh::ConversionResult::sourceExhausted:
139
0
      if (IgnoreInputErrors) {
140
0
        break;
141
0
      }
142
0
      return runtime.raiseRangeError(
143
0
          "Malformed UTF8 input: partial character in input");
144
0
    case llvh::ConversionResult::sourceIllegal:
145
0
      if (IgnoreInputErrors) {
146
0
        break;
147
0
      }
148
0
      return runtime.raiseRangeError("Malformed UTF8 input: illegal sequence");
149
0
    case llvh::ConversionResult::conversionOK:
150
0
      break;
151
0
    case llvh::ConversionResult::targetExhausted:
152
0
      return runtime.raiseRangeError(
153
0
          "Cannot allocate memory for UTF8 to UTF16 conversion.");
154
0
  }
155
156
0
  out.resize((char16_t *)targetStart - &out[0]);
157
0
  return ExecutionStatus::RETURNED;
158
0
}
159
160
CallResult<HermesValue> StringPrimitive::createEfficient(
161
    Runtime &runtime,
162
    UTF8Ref str,
163
0
    bool IgnoreInputErrors) {
164
0
  const uint8_t *utf8 = str.data();
165
0
  const size_t length = str.size();
166
0
  if (isAllASCII(utf8, utf8 + length)) {
167
0
    const char *ascii = reinterpret_cast<const char *>(utf8);
168
0
    return StringPrimitive::createEfficient(
169
0
        runtime, llvh::makeArrayRef(ascii, length));
170
0
  }
171
172
0
  std::u16string out;
173
0
  ExecutionStatus cRes =
174
0
      convertUtf8ToUtf16(runtime, str, IgnoreInputErrors, out);
175
0
  if (LLVM_UNLIKELY(cRes == ExecutionStatus::EXCEPTION)) {
176
0
    return ExecutionStatus::EXCEPTION;
177
0
  }
178
179
0
  return StringPrimitive::createEfficient(runtime, std::move(out));
180
0
}
181
182
CallResult<HermesValue> StringPrimitive::createEfficient(
183
    Runtime &runtime,
184
0
    UTF16Ref str) {
185
0
  return createEfficientImpl(runtime, str);
186
0
}
187
188
CallResult<HermesValue> StringPrimitive::createEfficient(
189
    Runtime &runtime,
190
0
    std::basic_string<char> &&str) {
191
0
  return createEfficientImpl(
192
0
      runtime, llvh::makeArrayRef(str.data(), str.size()), &str);
193
0
}
194
195
CallResult<HermesValue> StringPrimitive::createEfficient(
196
    Runtime &runtime,
197
0
    std::basic_string<char16_t> &&str) {
198
0
  return createEfficientImpl(
199
0
      runtime, llvh::makeArrayRef(str.data(), str.size()), &str);
200
0
}
201
202
CallResult<HermesValue> StringPrimitive::createDynamic(
203
    Runtime &runtime,
204
85.7k
    UTF16Ref str) {
205
85.7k
  return createDynamicWithKnownEncoding(
206
85.7k
      runtime, str, isAllASCII(str.begin(), str.end()));
207
85.7k
}
208
209
CallResult<HermesValue> StringPrimitive::createDynamicWithKnownEncoding(
210
    Runtime &runtime,
211
    UTF16Ref str,
212
85.7k
    bool isASCII) {
213
85.7k
  if (LLVM_LIKELY(isASCII)) {
214
85.7k
    auto res = DynamicASCIIStringPrimitive::create(runtime, str.size());
215
85.7k
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
216
0
      return ExecutionStatus::EXCEPTION;
217
0
    }
218
    // Copy directly into the StringPrimitive storage.
219
#ifdef _MSC_VER
220
#pragma warning(push)
221
#pragma warning(disable : 4244)
222
#endif
223
85.7k
    std::copy(
224
85.7k
        str.begin(), str.end(), res->getString()->castToASCIIPointerForWrite());
225
#ifdef _MSC_VER
226
#pragma warning(pop)
227
#endif
228
85.7k
    return res;
229
85.7k
  } else {
230
2
    return DynamicUTF16StringPrimitive::create(runtime, str);
231
2
  }
232
85.7k
}
233
234
bool StringPrimitive::sliceEquals(
235
    uint32_t start,
236
    uint32_t length,
237
387
    const StringPrimitive *other) const {
238
387
  if (isASCII()) {
239
193
    if (other->isASCII()) {
240
193
      return stringRefEquals(
241
193
          castToASCIIRef(start, length), other->castToASCIIRef());
242
193
    }
243
0
    return stringRefEquals(
244
0
        castToASCIIRef(start, length), other->castToUTF16Ref());
245
193
  }
246
194
  if (other->isASCII()) {
247
194
    return stringRefEquals(
248
194
        castToUTF16Ref(start, length), other->castToASCIIRef());
249
194
  }
250
0
  return stringRefEquals(
251
0
      castToUTF16Ref(start, length), other->castToUTF16Ref());
252
194
}
253
254
387
bool StringPrimitive::equals(const StringPrimitive *other) const {
255
387
  if (this == other) {
256
0
    return true;
257
0
  }
258
387
  return sliceEquals(0, getStringLength(), other);
259
387
}
260
261
156
bool StringPrimitive::equals(const StringView &other) const {
262
156
  if (isASCII()) {
263
64
    return other.equals(castToASCIIRef());
264
64
  }
265
92
  return other.equals(castToUTF16Ref());
266
156
}
267
268
0
int StringPrimitive::compare(const StringPrimitive *other) const {
269
0
  if (isASCII()) {
270
0
    if (other->isASCII()) {
271
0
      return stringRefCompare(castToASCIIRef(), other->castToASCIIRef());
272
0
    }
273
0
    return stringRefCompare(castToASCIIRef(), other->castToUTF16Ref());
274
0
  }
275
0
  if (other->isASCII()) {
276
0
    return stringRefCompare(castToUTF16Ref(), other->castToASCIIRef());
277
0
  }
278
0
  return stringRefCompare(castToUTF16Ref(), other->castToUTF16Ref());
279
0
}
280
281
CallResult<HermesValue> StringPrimitive::concat(
282
    Runtime &runtime,
283
    Handle<StringPrimitive> xHandle,
284
171k
    Handle<StringPrimitive> yHandle) {
285
171k
  auto *xPtr = xHandle.get();
286
171k
  auto *yPtr = yHandle.get();
287
288
171k
  auto xLen = xPtr->getStringLength();
289
171k
  auto yLen = yPtr->getStringLength();
290
171k
  if (!xLen) {
291
    // x is the empty string, just return y.
292
0
    return yHandle.getHermesValue();
293
0
  }
294
171k
  if (!yLen) {
295
    // y is the empty string, just return x.
296
85.6k
    return xHandle.getHermesValue();
297
85.6k
  }
298
299
85.8k
  SafeUInt32 xyLen(xLen);
300
85.8k
  xyLen.add(yLen);
301
85.8k
  if (xyLen.isOverflowed() || xyLen.get() > MAX_STRING_LENGTH) {
302
0
    return runtime.raiseRangeError("String length exceeds limit");
303
0
  }
304
305
85.8k
  if (xyLen.get() >= CONCAT_STRING_MIN_SIZE ||
306
85.8k
      isBufferedStringPrimitive(xPtr)) {
307
89
    if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(xyLen.get()))) {
308
0
      return runtime.raiseRangeError(
309
0
          "Cannot allocate an external string primitive.");
310
0
    }
311
89
    return internalConcatStringPrimitives(runtime, xHandle, yHandle)
312
89
        .getHermesValue();
313
89
  }
314
315
85.7k
  auto builder = StringBuilder::createStringBuilder(
316
85.7k
      runtime, xyLen, xPtr->isASCII() && yPtr->isASCII());
317
85.7k
  if (builder == ExecutionStatus::EXCEPTION) {
318
0
    return ExecutionStatus::EXCEPTION;
319
0
  }
320
321
85.7k
  builder->appendStringPrim(xHandle);
322
85.7k
  builder->appendStringPrim(yHandle);
323
85.7k
  return HermesValue::encodeStringValue(*builder->getStringPrimitive());
324
85.7k
}
325
326
CallResult<HermesValue> StringPrimitive::slice(
327
    Runtime &runtime,
328
    Handle<StringPrimitive> str,
329
    size_t start,
330
166k
    size_t length) {
331
166k
  assert(
332
166k
      start + length <= str->getStringLength() && "Invalid length for slice");
333
334
166k
  SafeUInt32 safeLen(length);
335
336
166k
  auto builder =
337
166k
      StringBuilder::createStringBuilder(runtime, safeLen, str->isASCII());
338
166k
  if (builder == ExecutionStatus::EXCEPTION) {
339
0
    return ExecutionStatus::EXCEPTION;
340
0
  }
341
166k
  if (str->isASCII()) {
342
0
    builder->appendASCIIRef(
343
0
        ASCIIRef(str->castToASCIIPointer() + start, length));
344
166k
  } else {
345
166k
    builder->appendUTF16Ref(
346
166k
        UTF16Ref(str->castToUTF16Pointer() + start, length));
347
166k
  }
348
166k
  return HermesValue::encodeStringValue(*builder->getStringPrimitive());
349
166k
}
350
351
StringView StringPrimitive::createStringView(
352
    Runtime &runtime,
353
515k
    Handle<StringPrimitive> self) {
354
515k
  ensureFlat(runtime, self);
355
515k
  return createStringViewMustBeFlat(self);
356
515k
}
357
358
void StringPrimitive::appendUTF16String(
359
122k
    llvh::SmallVectorImpl<char16_t> &str) const {
360
122k
  if (isASCII()) {
361
122k
    const char *ptr = castToASCIIPointer();
362
122k
    str.append(ptr, ptr + getStringLength());
363
122k
  } else {
364
75
    const char16_t *ptr = castToUTF16Pointer();
365
75
    str.append(ptr, ptr + getStringLength());
366
75
  }
367
122k
}
368
369
0
void StringPrimitive::appendUTF16String(char16_t *ptr) const {
370
0
  if (isASCII()) {
371
0
    const char *src = castToASCIIPointer();
372
0
    std::copy(src, src + getStringLength(), ptr);
373
0
  } else {
374
0
    const char16_t *src = castToUTF16Pointer();
375
0
    std::copy(src, src + getStringLength(), ptr);
376
0
  }
377
0
}
378
379
StringView StringPrimitive::createStringViewMustBeFlat(
380
799k
    Handle<StringPrimitive> self) {
381
799k
  return StringView(self);
382
799k
}
383
384
#ifdef HERMES_MEMORY_INSTRUMENTATION
385
0
std::string StringPrimitive::_snapshotNameImpl(GCCell *cell, GC &gc) {
386
0
  auto *const self = vmcast<StringPrimitive>(cell);
387
  // Only convert up to EXTERNAL_STRING_THRESHOLD characters, because large
388
  // strings can cause crashes in the snapshot visualizer.
389
0
  std::string out;
390
0
  bool fullyWritten = true;
391
0
  if (self->isASCII()) {
392
0
    auto ref = self->castToASCIIRef();
393
0
    out = std::string{
394
0
        ref.begin(),
395
0
        std::min(
396
0
            static_cast<uint32_t>(ref.size()),
397
0
            toRValue(EXTERNAL_STRING_THRESHOLD))};
398
0
    fullyWritten = ref.size() <= EXTERNAL_STRING_THRESHOLD;
399
0
  } else {
400
0
    fullyWritten = convertUTF16ToUTF8WithReplacements(
401
0
        out, self->castToUTF16Ref(), EXTERNAL_STRING_THRESHOLD);
402
0
  }
403
0
  if (!fullyWritten) {
404
    // The string was truncated, add a truncation message
405
0
    out += "...(truncated by snapshot)...";
406
0
  }
407
0
  return out;
408
0
}
409
#endif
410
411
template <typename T, bool Uniqued>
412
DynamicStringPrimitive<T, Uniqued>::DynamicStringPrimitive(Ref src)
413
959k
    : DynamicStringPrimitive((uint32_t)src.size()) {
414
959k
  hermes::uninitializedCopy(
415
959k
      src.begin(), src.end(), this->template getTrailingObjects<T>());
416
959k
}
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>::DynamicStringPrimitive(llvh::ArrayRef<char16_t>)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>::DynamicStringPrimitive(llvh::ArrayRef<char>)
hermes::vm::DynamicStringPrimitive<char16_t, false>::DynamicStringPrimitive(llvh::ArrayRef<char16_t>)
Line
Count
Source
413
6.78k
    : DynamicStringPrimitive((uint32_t)src.size()) {
414
6.78k
  hermes::uninitializedCopy(
415
6.78k
      src.begin(), src.end(), this->template getTrailingObjects<T>());
416
6.78k
}
hermes::vm::DynamicStringPrimitive<char, false>::DynamicStringPrimitive(llvh::ArrayRef<char>)
Line
Count
Source
413
952k
    : DynamicStringPrimitive((uint32_t)src.size()) {
414
952k
  hermes::uninitializedCopy(
415
952k
      src.begin(), src.end(), this->template getTrailingObjects<T>());
416
952k
}
417
418
template <typename T, bool Uniqued>
419
CallResult<HermesValue> DynamicStringPrimitive<T, Uniqued>::create(
420
    Runtime &runtime,
421
945k
    Ref str) {
422
945k
  assert(!isExternalLength(str.size()) && "length should not be external");
423
945k
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
424
945k
      allocationSize((uint32_t)str.size()), str);
425
945k
  return HermesValue::encodeStringValue(cell);
426
945k
}
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>::create(hermes::vm::Runtime&, llvh::ArrayRef<char16_t>)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>::create(hermes::vm::Runtime&, llvh::ArrayRef<char>)
hermes::vm::DynamicStringPrimitive<char16_t, false>::create(hermes::vm::Runtime&, llvh::ArrayRef<char16_t>)
Line
Count
Source
421
2
    Ref str) {
422
2
  assert(!isExternalLength(str.size()) && "length should not be external");
423
2
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
424
2
      allocationSize((uint32_t)str.size()), str);
425
2
  return HermesValue::encodeStringValue(cell);
426
2
}
hermes::vm::DynamicStringPrimitive<char, false>::create(hermes::vm::Runtime&, llvh::ArrayRef<char>)
Line
Count
Source
421
945k
    Ref str) {
422
945k
  assert(!isExternalLength(str.size()) && "length should not be external");
423
945k
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
424
945k
      allocationSize((uint32_t)str.size()), str);
425
945k
  return HermesValue::encodeStringValue(cell);
426
945k
}
427
428
template <typename T, bool Uniqued>
429
CallResult<HermesValue> DynamicStringPrimitive<T, Uniqued>::createLongLived(
430
    Runtime &runtime,
431
13.5k
    Ref str) {
432
13.5k
  assert(!isExternalLength(str.size()) && "length should not be external");
433
13.5k
  auto *obj = runtime.makeAVariable<
434
13.5k
      DynamicStringPrimitive<T, Uniqued>,
435
13.5k
      HasFinalizer::No,
436
13.5k
      LongLived::Yes>(allocationSize((uint32_t)str.size()), str);
437
13.5k
  return HermesValue::encodeStringValue(obj);
438
13.5k
}
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>::createLongLived(hermes::vm::Runtime&, llvh::ArrayRef<char16_t>)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>::createLongLived(hermes::vm::Runtime&, llvh::ArrayRef<char>)
hermes::vm::DynamicStringPrimitive<char16_t, false>::createLongLived(hermes::vm::Runtime&, llvh::ArrayRef<char16_t>)
Line
Count
Source
431
6.78k
    Ref str) {
432
6.78k
  assert(!isExternalLength(str.size()) && "length should not be external");
433
6.78k
  auto *obj = runtime.makeAVariable<
434
6.78k
      DynamicStringPrimitive<T, Uniqued>,
435
6.78k
      HasFinalizer::No,
436
6.78k
      LongLived::Yes>(allocationSize((uint32_t)str.size()), str);
437
6.78k
  return HermesValue::encodeStringValue(obj);
438
6.78k
}
hermes::vm::DynamicStringPrimitive<char, false>::createLongLived(hermes::vm::Runtime&, llvh::ArrayRef<char>)
Line
Count
Source
431
6.78k
    Ref str) {
432
6.78k
  assert(!isExternalLength(str.size()) && "length should not be external");
433
6.78k
  auto *obj = runtime.makeAVariable<
434
6.78k
      DynamicStringPrimitive<T, Uniqued>,
435
6.78k
      HasFinalizer::No,
436
6.78k
      LongLived::Yes>(allocationSize((uint32_t)str.size()), str);
437
6.78k
  return HermesValue::encodeStringValue(obj);
438
6.78k
}
439
440
template <typename T, bool Uniqued>
441
CallResult<HermesValue> DynamicStringPrimitive<T, Uniqued>::create(
442
    Runtime &runtime,
443
680k
    uint32_t length) {
444
680k
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
445
680k
      allocationSize(length), length);
446
680k
  return HermesValue::encodeStringValue(cell);
447
680k
}
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char16_t, true>::create(hermes::vm::Runtime&, unsigned int)
Unexecuted instantiation: hermes::vm::DynamicStringPrimitive<char, true>::create(hermes::vm::Runtime&, unsigned int)
hermes::vm::DynamicStringPrimitive<char16_t, false>::create(hermes::vm::Runtime&, unsigned int)
Line
Count
Source
443
252k
    uint32_t length) {
444
252k
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
445
252k
      allocationSize(length), length);
446
252k
  return HermesValue::encodeStringValue(cell);
447
252k
}
hermes::vm::DynamicStringPrimitive<char, false>::create(hermes::vm::Runtime&, unsigned int)
Line
Count
Source
443
428k
    uint32_t length) {
444
428k
  auto *cell = runtime.makeAVariable<DynamicStringPrimitive<T, Uniqued>>(
445
428k
      allocationSize(length), length);
446
428k
  return HermesValue::encodeStringValue(cell);
447
428k
}
448
449
template class DynamicStringPrimitive<char16_t, true /* Uniqued */>;
450
template class DynamicStringPrimitive<char, true /* Uniqued */>;
451
template class DynamicStringPrimitive<char16_t, false /* not Uniqued */>;
452
template class DynamicStringPrimitive<char, false /* not Uniqued */>;
453
454
// NOTE: this is a template method in a template class, thus the two separate
455
// template<> lines.
456
template <typename T>
457
template <class BasicString>
458
ExternalStringPrimitive<T>::ExternalStringPrimitive(BasicString &&contents)
459
138
    : SymbolStringPrimitive(contents.size()),
460
138
      contents_(std::forward<BasicString>(contents)) {
461
138
  static_assert(
462
138
      std::is_same<T, typename BasicString::value_type>::value,
463
138
      "ExternalStringPrimitive mismatched char type");
464
138
  assert(
465
138
      getStringLength() >= EXTERNAL_STRING_MIN_SIZE &&
466
138
      "ExternalStringPrimitive length must be at least EXTERNAL_STRING_MIN_SIZE");
467
138
}
hermes::vm::ExternalStringPrimitive<char16_t>::ExternalStringPrimitive<std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> > >(std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >&&)
Line
Count
Source
459
132
    : SymbolStringPrimitive(contents.size()),
460
132
      contents_(std::forward<BasicString>(contents)) {
461
132
  static_assert(
462
132
      std::is_same<T, typename BasicString::value_type>::value,
463
132
      "ExternalStringPrimitive mismatched char type");
464
132
  assert(
465
132
      getStringLength() >= EXTERNAL_STRING_MIN_SIZE &&
466
132
      "ExternalStringPrimitive length must be at least EXTERNAL_STRING_MIN_SIZE");
467
132
}
hermes::vm::ExternalStringPrimitive<char>::ExternalStringPrimitive<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
459
6
    : SymbolStringPrimitive(contents.size()),
460
6
      contents_(std::forward<BasicString>(contents)) {
461
6
  static_assert(
462
6
      std::is_same<T, typename BasicString::value_type>::value,
463
6
      "ExternalStringPrimitive mismatched char type");
464
6
  assert(
465
6
      getStringLength() >= EXTERNAL_STRING_MIN_SIZE &&
466
6
      "ExternalStringPrimitive length must be at least EXTERNAL_STRING_MIN_SIZE");
467
6
}
468
469
// NOTE: this is a template method in a template class, thus the two separate
470
// template<> lines.
471
template <typename T>
472
template <class BasicString>
473
CallResult<HermesValue> ExternalStringPrimitive<T>::create(
474
    Runtime &runtime,
475
125
    BasicString &&str) {
476
125
  static_assert(
477
125
      std::is_same<T, typename BasicString::value_type>::value,
478
125
      "ExternalStringPrimitive mismatched char type");
479
125
  if (LLVM_UNLIKELY(str.size() > MAX_STRING_LENGTH))
480
0
    return runtime.raiseRangeError("String length exceeds limit");
481
  // We have to use a variable sized alloc here even though the size is already
482
  // known, because ExternalStringPrimitive is derived from
483
  // VariableSizeRuntimeCell
484
125
  auto *extStr =
485
125
      runtime.makeAVariable<ExternalStringPrimitive<T>, HasFinalizer::Yes>(
486
125
          sizeof(ExternalStringPrimitive<T>), std::forward<BasicString>(str));
487
125
  runtime.getHeap().creditExternalMemory(
488
125
      extStr, extStr->calcExternalMemorySize());
489
125
  auto res = HermesValue::encodeStringValue(extStr);
490
125
  return res;
491
125
}
Unexecuted instantiation: hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::ExternalStringPrimitive<char>::create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(hermes::vm::Runtime&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
hermes::vm::CallResult<hermes::vm::HermesValue, (hermes::vm::detail::CallResultSpecialize)2> hermes::vm::ExternalStringPrimitive<char16_t>::create<std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> > >(hermes::vm::Runtime&, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >&&)
Line
Count
Source
475
125
    BasicString &&str) {
476
125
  static_assert(
477
125
      std::is_same<T, typename BasicString::value_type>::value,
478
125
      "ExternalStringPrimitive mismatched char type");
479
125
  if (LLVM_UNLIKELY(str.size() > MAX_STRING_LENGTH))
480
0
    return runtime.raiseRangeError("String length exceeds limit");
481
  // We have to use a variable sized alloc here even though the size is already
482
  // known, because ExternalStringPrimitive is derived from
483
  // VariableSizeRuntimeCell
484
125
  auto *extStr =
485
125
      runtime.makeAVariable<ExternalStringPrimitive<T>, HasFinalizer::Yes>(
486
125
          sizeof(ExternalStringPrimitive<T>), std::forward<BasicString>(str));
487
125
  runtime.getHeap().creditExternalMemory(
488
125
      extStr, extStr->calcExternalMemorySize());
489
125
  auto res = HermesValue::encodeStringValue(extStr);
490
125
  return res;
491
125
}
492
493
template <typename T>
494
CallResult<HermesValue> ExternalStringPrimitive<T>::createLongLived(
495
    Runtime &runtime,
496
13
    StdString &&str) {
497
13
  if (LLVM_UNLIKELY(str.size() > MAX_STRING_LENGTH))
498
0
    return runtime.raiseRangeError("String length exceeds limit");
499
13
  if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(
500
13
          str.capacity() * sizeof(T)))) {
501
0
    return runtime.raiseRangeError(
502
0
        "Cannot allocate an external string primitive.");
503
0
  }
504
  // Use variable size alloc since ExternalStringPrimitive is derived from
505
  // VariableSizeRuntimeCell.
506
13
  auto *extStr = runtime.makeAVariable<
507
13
      ExternalStringPrimitive<T>,
508
13
      HasFinalizer::Yes,
509
13
      LongLived::Yes>(sizeof(ExternalStringPrimitive<T>), std::move(str));
510
13
  runtime.getHeap().creditExternalMemory(
511
13
      extStr, extStr->calcExternalMemorySize());
512
13
  return HermesValue::encodeStringValue(extStr);
513
13
}
hermes::vm::ExternalStringPrimitive<char16_t>::createLongLived(hermes::vm::Runtime&, std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, std::__1::allocator<char16_t> >&&)
Line
Count
Source
496
7
    StdString &&str) {
497
7
  if (LLVM_UNLIKELY(str.size() > MAX_STRING_LENGTH))
498
0
    return runtime.raiseRangeError("String length exceeds limit");
499
7
  if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(
500
7
          str.capacity() * sizeof(T)))) {
501
0
    return runtime.raiseRangeError(
502
0
        "Cannot allocate an external string primitive.");
503
0
  }
504
  // Use variable size alloc since ExternalStringPrimitive is derived from
505
  // VariableSizeRuntimeCell.
506
7
  auto *extStr = runtime.makeAVariable<
507
7
      ExternalStringPrimitive<T>,
508
7
      HasFinalizer::Yes,
509
7
      LongLived::Yes>(sizeof(ExternalStringPrimitive<T>), std::move(str));
510
7
  runtime.getHeap().creditExternalMemory(
511
7
      extStr, extStr->calcExternalMemorySize());
512
7
  return HermesValue::encodeStringValue(extStr);
513
7
}
hermes::vm::ExternalStringPrimitive<char>::createLongLived(hermes::vm::Runtime&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Line
Count
Source
496
6
    StdString &&str) {
497
6
  if (LLVM_UNLIKELY(str.size() > MAX_STRING_LENGTH))
498
0
    return runtime.raiseRangeError("String length exceeds limit");
499
6
  if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(
500
6
          str.capacity() * sizeof(T)))) {
501
0
    return runtime.raiseRangeError(
502
0
        "Cannot allocate an external string primitive.");
503
0
  }
504
  // Use variable size alloc since ExternalStringPrimitive is derived from
505
  // VariableSizeRuntimeCell.
506
6
  auto *extStr = runtime.makeAVariable<
507
6
      ExternalStringPrimitive<T>,
508
6
      HasFinalizer::Yes,
509
6
      LongLived::Yes>(sizeof(ExternalStringPrimitive<T>), std::move(str));
510
6
  runtime.getHeap().creditExternalMemory(
511
6
      extStr, extStr->calcExternalMemorySize());
512
6
  return HermesValue::encodeStringValue(extStr);
513
6
}
514
515
template <typename T>
516
CallResult<HermesValue> ExternalStringPrimitive<T>::create(
517
    Runtime &runtime,
518
88
    uint32_t length) {
519
88
  assert(isExternalLength(length) && "length should be external");
520
88
  if (LLVM_UNLIKELY(length > MAX_STRING_LENGTH))
521
0
    return runtime.raiseRangeError("String length exceeds limit");
522
88
  uint32_t allocSize = length * sizeof(T);
523
88
  if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(allocSize))) {
524
0
    return runtime.raiseRangeError(
525
0
        "Cannot allocate an external string primitive.");
526
0
  }
527
88
  return create(runtime, StdString(length, T(0)));
528
88
}
hermes::vm::ExternalStringPrimitive<char16_t>::create(hermes::vm::Runtime&, unsigned int)
Line
Count
Source
518
88
    uint32_t length) {
519
88
  assert(isExternalLength(length) && "length should be external");
520
88
  if (LLVM_UNLIKELY(length > MAX_STRING_LENGTH))
521
0
    return runtime.raiseRangeError("String length exceeds limit");
522
88
  uint32_t allocSize = length * sizeof(T);
523
88
  if (LLVM_UNLIKELY(!runtime.getHeap().canAllocExternalMemory(allocSize))) {
524
0
    return runtime.raiseRangeError(
525
0
        "Cannot allocate an external string primitive.");
526
0
  }
527
88
  return create(runtime, StdString(length, T(0)));
528
88
}
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char>::create(hermes::vm::Runtime&, unsigned int)
529
530
template <typename T>
531
138
void ExternalStringPrimitive<T>::_finalizeImpl(GCCell *cell, GC &gc) {
532
138
  ExternalStringPrimitive<T> *self = vmcast<ExternalStringPrimitive<T>>(cell);
533
  // Remove the external string from the snapshot tracking system if it's being
534
  // tracked.
535
138
  gc.getIDTracker().untrackNative(self->contents_.data());
536
138
  gc.debitExternalMemory(self, self->calcExternalMemorySize());
537
138
  self->~ExternalStringPrimitive<T>();
538
138
}
hermes::vm::ExternalStringPrimitive<char16_t>::_finalizeImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&)
Line
Count
Source
531
132
void ExternalStringPrimitive<T>::_finalizeImpl(GCCell *cell, GC &gc) {
532
132
  ExternalStringPrimitive<T> *self = vmcast<ExternalStringPrimitive<T>>(cell);
533
  // Remove the external string from the snapshot tracking system if it's being
534
  // tracked.
535
132
  gc.getIDTracker().untrackNative(self->contents_.data());
536
132
  gc.debitExternalMemory(self, self->calcExternalMemorySize());
537
132
  self->~ExternalStringPrimitive<T>();
538
132
}
hermes::vm::ExternalStringPrimitive<char>::_finalizeImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&)
Line
Count
Source
531
6
void ExternalStringPrimitive<T>::_finalizeImpl(GCCell *cell, GC &gc) {
532
6
  ExternalStringPrimitive<T> *self = vmcast<ExternalStringPrimitive<T>>(cell);
533
  // Remove the external string from the snapshot tracking system if it's being
534
  // tracked.
535
6
  gc.getIDTracker().untrackNative(self->contents_.data());
536
6
  gc.debitExternalMemory(self, self->calcExternalMemorySize());
537
6
  self->~ExternalStringPrimitive<T>();
538
6
}
539
540
template <typename T>
541
0
size_t ExternalStringPrimitive<T>::_mallocSizeImpl(GCCell *cell) {
542
0
  ExternalStringPrimitive<T> *self = vmcast<ExternalStringPrimitive<T>>(cell);
543
0
  return self->calcExternalMemorySize();
544
0
}
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char16_t>::_mallocSizeImpl(hermes::vm::GCCell*)
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char>::_mallocSizeImpl(hermes::vm::GCCell*)
545
546
#ifdef HERMES_MEMORY_INSTRUMENTATION
547
template <typename T>
548
void ExternalStringPrimitive<T>::_snapshotAddEdgesImpl(
549
    GCCell *cell,
550
    GC &gc,
551
0
    HeapSnapshot &snap) {
552
0
  auto *const self = vmcast<ExternalStringPrimitive<T>>(cell);
553
0
  snap.addNamedEdge(
554
0
      HeapSnapshot::EdgeType::Internal,
555
0
      "externalString",
556
0
      gc.getNativeID(self->contents_.data()));
557
0
}
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char16_t>::_snapshotAddEdgesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char>::_snapshotAddEdgesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
558
559
template <typename T>
560
void ExternalStringPrimitive<T>::_snapshotAddNodesImpl(
561
    GCCell *cell,
562
    GC &gc,
563
0
    HeapSnapshot &snap) {
564
0
  auto *const self = vmcast<ExternalStringPrimitive<T>>(cell);
565
0
  snap.beginNode();
566
0
  snap.endNode(
567
0
      HeapSnapshot::NodeType::Native,
568
0
      "ExternalStringPrimitive",
569
0
      gc.getNativeID(self->contents_.data()),
570
0
      self->contents_.size(),
571
0
      0);
572
0
}
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char16_t>::_snapshotAddNodesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
Unexecuted instantiation: hermes::vm::ExternalStringPrimitive<char>::_snapshotAddNodesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
573
#endif
574
575
template class ExternalStringPrimitive<char16_t>;
576
template class ExternalStringPrimitive<char>;
577
578
template CallResult<HermesValue> ExternalStringPrimitive<char>::create<
579
    std::basic_string<char>>(Runtime &runtime, std::basic_string<char> &&str);
580
581
template CallResult<HermesValue>
582
ExternalStringPrimitive<char16_t>::create<std::basic_string<char16_t>>(
583
    Runtime &runtime,
584
    std::basic_string<char16_t> &&str);
585
586
//===----------------------------------------------------------------------===//
587
// BufferedStringPrimitive<T>
588
589
void BufferedASCIIStringPrimitiveBuildMeta(
590
    const GCCell *cell,
591
1
    Metadata::Builder &mb) {
592
1
  const auto *self = static_cast<const BufferedASCIIStringPrimitive *>(cell);
593
1
  mb.setVTable(&BufferedASCIIStringPrimitive::vt);
594
1
  mb.addField("storage", &self->concatBufferHV_);
595
1
}
596
void BufferedUTF16StringPrimitiveBuildMeta(
597
    const GCCell *cell,
598
1
    Metadata::Builder &mb) {
599
1
  const auto *self = static_cast<const BufferedUTF16StringPrimitive *>(cell);
600
1
  mb.setVTable(&BufferedUTF16StringPrimitive::vt);
601
1
  mb.addField("storage", &self->concatBufferHV_);
602
1
}
603
604
template <typename T>
605
PseudoHandle<StringPrimitive> BufferedStringPrimitive<T>::create(
606
    Runtime &runtime,
607
    uint32_t length,
608
89
    Handle<ExternalStringPrimitive<T>> storage) {
609
  // We have to use a variable sized alloc here even though the size is already
610
  // known, because BufferedStringPrimitive is derived from
611
  // VariableSizeRuntimeCell.
612
89
  auto *cell = runtime.makeAVariable<BufferedStringPrimitive<T>>(
613
89
      sizeof(BufferedStringPrimitive<T>), runtime, length, storage);
614
89
  return createPseudoHandle<StringPrimitive>(cell);
615
89
}
hermes::vm::BufferedStringPrimitive<char16_t>::create(hermes::vm::Runtime&, unsigned int, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char16_t> >)
Line
Count
Source
608
89
    Handle<ExternalStringPrimitive<T>> storage) {
609
  // We have to use a variable sized alloc here even though the size is already
610
  // known, because BufferedStringPrimitive is derived from
611
  // VariableSizeRuntimeCell.
612
89
  auto *cell = runtime.makeAVariable<BufferedStringPrimitive<T>>(
613
89
      sizeof(BufferedStringPrimitive<T>), runtime, length, storage);
614
89
  return createPseudoHandle<StringPrimitive>(cell);
615
89
}
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char>::create(hermes::vm::Runtime&, unsigned int, hermes::vm::Handle<hermes::vm::ExternalStringPrimitive<char> >)
616
617
#ifndef NDEBUG
618
/// Assert the the combined length of the two strings is valid.
619
178
static void assertValidLength(StringPrimitive *a, StringPrimitive *b) {
620
178
  SafeUInt32 len(a->getStringLength());
621
178
  len.add(b->getStringLength());
622
178
  assert(
623
178
      !len.isOverflowed() && len.get() <= StringPrimitive::MAX_STRING_LENGTH &&
624
178
      "length must have been validated");
625
178
}
626
#else
627
static inline void assertValidLength(StringPrimitive *a, StringPrimitive *b) {}
628
#endif
629
630
template <>
631
void BufferedStringPrimitive<char>::appendToCopyableString(
632
    CopyableBasicString<char> &res,
633
0
    const StringPrimitive *str) {
634
0
  auto it = str->castToASCIIPointer();
635
0
  res.append(it, it + str->getStringLength());
636
0
}
637
template <>
638
void BufferedStringPrimitive<char16_t>::appendToCopyableString(
639
    CopyableBasicString<char16_t> &res,
640
112
    const StringPrimitive *str) {
641
112
  if (str->isASCII()) {
642
87
    auto it = (const uint8_t *)str->castToASCIIPointer();
643
87
    res.append(it, it + str->getStringLength());
644
87
  } else {
645
25
    auto it = str->castToUTF16Pointer();
646
25
    res.append(it, it + str->getStringLength());
647
25
  }
648
112
}
649
650
template <typename T>
651
PseudoHandle<StringPrimitive> BufferedStringPrimitive<T>::create(
652
    Runtime &runtime,
653
    Handle<StringPrimitive> leftHnd,
654
23
    Handle<StringPrimitive> rightHnd) {
655
23
  typename ExternalStringPrimitive<T>::CopyableStdString contents{};
656
23
  uint32_t len;
657
658
23
  {
659
23
    NoAllocScope noAlloc{runtime};
660
23
    auto *left = leftHnd.get();
661
23
    auto *right = rightHnd.get();
662
663
23
    assertValidLength(left, right);
664
23
    len = left->getStringLength() + right->getStringLength();
665
666
23
    contents.reserve(len);
667
23
    appendToCopyableString(contents, left);
668
23
    appendToCopyableString(contents, right);
669
23
  }
670
671
23
  auto storageHnd = runtime.makeHandle<ExternalStringPrimitive<T>>(
672
23
      runtime.ignoreAllocationFailure(
673
23
          ExternalStringPrimitive<T>::create(runtime, std::move(contents))));
674
675
23
  return create(runtime, len, storageHnd);
676
23
}
hermes::vm::BufferedStringPrimitive<char16_t>::create(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>, hermes::vm::Handle<hermes::vm::StringPrimitive>)
Line
Count
Source
654
23
    Handle<StringPrimitive> rightHnd) {
655
23
  typename ExternalStringPrimitive<T>::CopyableStdString contents{};
656
23
  uint32_t len;
657
658
23
  {
659
23
    NoAllocScope noAlloc{runtime};
660
23
    auto *left = leftHnd.get();
661
23
    auto *right = rightHnd.get();
662
663
23
    assertValidLength(left, right);
664
23
    len = left->getStringLength() + right->getStringLength();
665
666
23
    contents.reserve(len);
667
23
    appendToCopyableString(contents, left);
668
23
    appendToCopyableString(contents, right);
669
23
  }
670
671
23
  auto storageHnd = runtime.makeHandle<ExternalStringPrimitive<T>>(
672
23
      runtime.ignoreAllocationFailure(
673
23
          ExternalStringPrimitive<T>::create(runtime, std::move(contents))));
674
675
23
  return create(runtime, len, storageHnd);
676
23
}
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char>::create(hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>, hermes::vm::Handle<hermes::vm::StringPrimitive>)
677
678
template <typename T>
679
PseudoHandle<StringPrimitive> BufferedStringPrimitive<T>::append(
680
    Handle<BufferedStringPrimitive<T>> selfHnd,
681
    Runtime &runtime,
682
66
    Handle<StringPrimitive> rightHnd) {
683
66
  NoAllocScope noAlloc{runtime};
684
66
  auto *self = selfHnd.get();
685
66
  auto *right = rightHnd.get();
686
66
  ExternalStringPrimitive<T> *storage = self->getConcatBuffer();
687
688
66
  assertValidLength(self, right);
689
66
  assert(
690
66
      (std::is_same<T, char16_t>::value || right->isASCII()) &&
691
66
      "cannot append UTF16 to ASCII");
692
693
  // Can't append if this is not the end of the string.
694
66
  if (self->getStringLength() != storage->contents_.size()) {
695
0
    noAlloc.release();
696
0
    return BufferedStringPrimitive<T>::create(runtime, selfHnd, rightHnd);
697
0
  }
698
699
66
  auto oldExternalMem = storage->calcExternalMemorySize();
700
66
  appendToCopyableString(storage->contents_, right);
701
66
  runtime.getHeap().creditExternalMemory(
702
66
      storage, storage->calcExternalMemorySize() - oldExternalMem);
703
704
66
  noAlloc.release();
705
66
  return BufferedStringPrimitive<T>::create(
706
66
      runtime, storage->contents_.size(), runtime.makeHandle(storage));
707
66
}
hermes::vm::BufferedStringPrimitive<char16_t>::append(hermes::vm::Handle<hermes::vm::BufferedStringPrimitive<char16_t> >, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>)
Line
Count
Source
682
66
    Handle<StringPrimitive> rightHnd) {
683
66
  NoAllocScope noAlloc{runtime};
684
66
  auto *self = selfHnd.get();
685
66
  auto *right = rightHnd.get();
686
66
  ExternalStringPrimitive<T> *storage = self->getConcatBuffer();
687
688
66
  assertValidLength(self, right);
689
66
  assert(
690
66
      (std::is_same<T, char16_t>::value || right->isASCII()) &&
691
66
      "cannot append UTF16 to ASCII");
692
693
  // Can't append if this is not the end of the string.
694
66
  if (self->getStringLength() != storage->contents_.size()) {
695
0
    noAlloc.release();
696
0
    return BufferedStringPrimitive<T>::create(runtime, selfHnd, rightHnd);
697
0
  }
698
699
66
  auto oldExternalMem = storage->calcExternalMemorySize();
700
66
  appendToCopyableString(storage->contents_, right);
701
66
  runtime.getHeap().creditExternalMemory(
702
66
      storage, storage->calcExternalMemorySize() - oldExternalMem);
703
704
66
  noAlloc.release();
705
66
  return BufferedStringPrimitive<T>::create(
706
66
      runtime, storage->contents_.size(), runtime.makeHandle(storage));
707
66
}
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char>::append(hermes::vm::Handle<hermes::vm::BufferedStringPrimitive<char> >, hermes::vm::Runtime&, hermes::vm::Handle<hermes::vm::StringPrimitive>)
708
709
PseudoHandle<StringPrimitive> internalConcatStringPrimitives(
710
    Runtime &runtime,
711
    Handle<StringPrimitive> leftHnd,
712
89
    Handle<StringPrimitive> rightHnd) {
713
89
  auto *left = leftHnd.get();
714
89
  auto *right = rightHnd.get();
715
716
89
  assertValidLength(left, right);
717
718
89
  if (left->isASCII() && right->isASCII()) {
719
0
    if (auto *bufLeft = dyn_vmcast<BufferedASCIIStringPrimitive>(left)) {
720
0
      if (bufLeft->getStringLength() ==
721
0
          bufLeft->getConcatBuffer()->contents_.size())
722
0
        return BufferedASCIIStringPrimitive::append(
723
0
            Handle<BufferedASCIIStringPrimitive>::vmcast(leftHnd),
724
0
            runtime,
725
0
            rightHnd);
726
0
    }
727
0
    return BufferedASCIIStringPrimitive::create(runtime, leftHnd, rightHnd);
728
89
  } else {
729
89
    if (auto *bufLeft = dyn_vmcast<BufferedUTF16StringPrimitive>(left)) {
730
66
      if (bufLeft->getStringLength() ==
731
66
          bufLeft->getConcatBuffer()->contents_.size()) {
732
66
        return BufferedUTF16StringPrimitive::append(
733
66
            Handle<BufferedUTF16StringPrimitive>::vmcast(leftHnd),
734
66
            runtime,
735
66
            rightHnd);
736
66
      }
737
66
    }
738
23
    return BufferedUTF16StringPrimitive::create(runtime, leftHnd, rightHnd);
739
89
  }
740
89
}
741
742
#ifdef HERMES_MEMORY_INSTRUMENTATION
743
template <typename T>
744
void BufferedStringPrimitive<T>::_snapshotAddEdgesImpl(
745
    GCCell *cell,
746
    GC &gc,
747
0
    HeapSnapshot &snap) {}
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char16_t>::_snapshotAddEdgesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char>::_snapshotAddEdgesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
748
749
template <typename T>
750
void BufferedStringPrimitive<T>::_snapshotAddNodesImpl(
751
    GCCell *cell,
752
    GC &gc,
753
0
    HeapSnapshot &snap) {}
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char16_t>::_snapshotAddNodesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
Unexecuted instantiation: hermes::vm::BufferedStringPrimitive<char>::_snapshotAddNodesImpl(hermes::vm::GCCell*, hermes::vm::HadesGC&, hermes::vm::HeapSnapshot&)
754
#endif
755
756
template class BufferedStringPrimitive<char16_t>;
757
template class BufferedStringPrimitive<char>;
758
} // namespace vm
759
} // namespace hermes