/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 |