v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-string-tsa.cc
Go to the documentation of this file.
1// Copyright 2024 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
11#include "src/objects/string.h"
13
14namespace v8::internal {
15
17
18using namespace compiler::turboshaft; // NOLINT(build/namespaces)
19
20template <typename Next>
21class StringBuiltinsReducer : public Next {
22 public:
23 BUILTIN_REDUCER(StringBuiltins)
24
25 void CopyStringCharacters(V<String> src_string, ConstOrV<WordPtr> src_begin,
26 String::Encoding src_encoding, V<String> dst_string,
27 ConstOrV<WordPtr> dst_begin,
28 String::Encoding dst_encoding,
29 ConstOrV<WordPtr> character_count) {
30 bool src_one_byte = src_encoding == String::ONE_BYTE_ENCODING;
31 bool dst_one_byte = dst_encoding == String::ONE_BYTE_ENCODING;
32 __ CodeComment("CopyStringCharacters ",
33 src_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING",
34 " -> ",
35 dst_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING");
36
37 const auto dst_rep = dst_one_byte ? MemoryRepresentation::Uint8()
41 const size_t data_offset = OFFSET_OF_DATA_START(SeqOneByteString);
42 const int dst_stride = dst_one_byte ? 1 : 2;
43
45 V<WordPtr> dst_begin_offset =
46 __ WordPtrAdd(__ BitcastTaggedToWordPtr(dst_string),
47 __ WordPtrAdd(data_offset - kHeapObjectTag,
48 __ WordPtrMul(dst_begin, dst_stride)));
49
50 StringView src_view(no_gc, src_string, src_encoding, src_begin,
51 character_count);
52 FOREACH(src_char, dst_offset,
53 Zip(src_view, Sequence(dst_begin_offset, dst_stride))) {
54#if DEBUG
55 // Copying two-byte characters to one-byte is okay if callers have
56 // checked that this loses no information.
57 if (v8_flags.debug_code && !src_one_byte && dst_one_byte) {
58 TSA_DCHECK(this, __ Uint32LessThanOrEqual(src_char, 0xFF));
59 }
60#endif
61 __ Store(dst_offset, src_char, StoreOp::Kind::RawAligned(), dst_rep,
63 }
64 }
65
67 __ CodeComment("AllocateSeqOneByteString");
68 Label<SeqOneByteString> done(this);
69 GOTO_IF(__ WordPtrEqual(length, 0), done,
70 V<SeqOneByteString>::Cast(__ EmptyStringConstant()));
71
72 V<WordPtr> object_size =
73 __ WordPtrAdd(sizeof(SeqOneByteString),
74 __ WordPtrMul(length, sizeof(SeqOneByteString::Char)));
75 V<WordPtr> aligned_size = __ AlignTagged(object_size);
77 __ template Allocate<SeqOneByteString>(aligned_size,
79 __ InitializeField(new_string, AccessBuilderTS::ForMap(),
80 __ SeqOneByteStringMapConstant());
81
82 __ InitializeField(new_string, AccessBuilderTS::ForStringLength(),
83 __ TruncateWordPtrToWord32(length));
84 __ InitializeField(new_string, AccessBuilderTS::ForNameRawHashField(),
86 V<SeqOneByteString> string = __ FinishInitialization(std::move(new_string));
87 // Clear padding.
88 V<WordPtr> raw_padding_begin = __ WordPtrAdd(
89 __ WordPtrAdd(__ BitcastTaggedToWordPtr(string), aligned_size),
91 static_assert(kObjectAlignment ==
93 __ Store(raw_padding_begin, {}, __ SmiConstant(0),
95 compiler::kNoWriteBarrier, 0, 0, true);
96 GOTO(done, string);
97
98 BIND(done, result);
99 return result;
100 }
101
103 __ CodeComment("AllocateSeqTwoByteString");
104 Label<SeqTwoByteString> done(this);
105 GOTO_IF(__ WordPtrEqual(length, 0), done,
106 V<SeqTwoByteString>::Cast(__ EmptyStringConstant()));
107
108 V<WordPtr> object_size =
109 __ WordPtrAdd(sizeof(SeqTwoByteString),
110 __ WordPtrMul(length, sizeof(SeqTwoByteString::Char)));
111 V<WordPtr> aligned_size = __ AlignTagged(object_size);
113 __ template Allocate<SeqTwoByteString>(aligned_size,
115 __ InitializeField(new_string, AccessBuilderTS::ForMap(),
116 __ SeqTwoByteStringMapConstant());
117
118 __ InitializeField(new_string, AccessBuilderTS::ForStringLength(),
119 __ TruncateWordPtrToWord32(length));
120 __ InitializeField(new_string, AccessBuilderTS::ForNameRawHashField(),
122 V<SeqTwoByteString> string = __ FinishInitialization(std::move(new_string));
123 // Clear padding.
124 V<WordPtr> raw_padding_begin = __ WordPtrAdd(
125 __ WordPtrAdd(__ BitcastTaggedToWordPtr(string), aligned_size),
127 static_assert(kObjectAlignment ==
129 __ Store(raw_padding_begin, {}, __ SmiConstant(0),
131 compiler::kNoWriteBarrier, 0, 0, true);
132 GOTO(done, string);
133
134 BIND(done, result);
135 return result;
136 }
137};
138
151
152#ifdef V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
153
154TS_BUILTIN(StringFromCodePointAt, StringBuiltinsAssemblerTS) {
155 auto receiver = Parameter<String>(Descriptor::kReceiver);
156 auto position = Parameter<WordPtr>(Descriptor::kPosition);
157
158 // Load the character code at the {position} from the {receiver}.
159 V<Word32> codepoint =
160 LoadSurrogatePairAt(receiver, {}, position, UnicodeEncoding::UTF16);
161 // Create a String from the UTF16 encoded code point
163 StringFromSingleCodePoint(codepoint, UnicodeEncoding::UTF16);
164 Return(result);
165}
166
167// ES6 #sec-string.fromcharcode
168TS_BUILTIN(StringFromCharCode, StringBuiltinsAssemblerTS) {
169 V<Context> context = Parameter<Context>(Descriptor::kContext);
170 V<Word32> argc = Parameter<Word32>(Descriptor::kJSActualArgumentsCount);
171 BuiltinArgumentsTS arguments(this, argc);
172
173 V<WordPtr> character_count = arguments.GetLengthWithoutReceiver();
174 // Check if we have exactly one argument (plus the implicit receiver), i.e.
175 // if the parent frame is not an inlined arguments frame.
176 IF (WordPtrEqual(arguments.GetLengthWithoutReceiver(), 1)) {
177 // Single argument case, perform fast single character string cache lookup
178 // for one-byte code units, or fall back to creating a single character
179 // string on the fly otherwise.
180 V<Object> code = arguments.AtIndex(0);
181 V<Word32> code32 = TruncateTaggedToWord32(context, code);
182 V<Word32> code16 = Word32BitwiseAnd(code32, String::kMaxUtf16CodeUnit);
183 V<String> result = StringFromSingleCharCode(code16);
184 PopAndReturn(arguments, result);
185 } ELSE {
186 Label<> contains_two_byte_characters(this);
187
188 // Assume that the resulting string contains only one-byte characters.
189 V<SeqOneByteString> one_byte_result =
190 AllocateSeqOneByteString(character_count);
191
192 ScopedVar<WordPtr> var_max_index(this, 0);
193 // Iterate over the incoming arguments, converting them to 8-bit character
194 // codes. Stop if any of the conversions generates a code that doesn't fit
195 // in 8 bits.
196 FOREACH(arg, arguments.Range()) {
197 V<Word32> code32 = TruncateTaggedToWord32(context, arg);
198 V<Word32> code16 = Word32BitwiseAnd(code32, String::kMaxUtf16CodeUnit);
199
200 IF (UNLIKELY(Int32LessThan(String::kMaxOneByteCharCode, code16))) {
201 // At least one of the characters in the string requires a 16-bit
202 // representation. Allocate a SeqTwoByteString to hold the resulting
203 // string.
204 V<SeqTwoByteString> two_byte_result =
205 AllocateSeqTwoByteString(character_count);
206
207 // Copy the characters that have already been put in the 8-bit string
208 // into their corresponding positions in the new 16-bit string.
209 CopyStringCharacters(one_byte_result, 0, String::ONE_BYTE_ENCODING,
210 two_byte_result, 0, String::TWO_BYTE_ENCODING,
211 var_max_index);
212
213 // Write the character that caused the 8-bit to 16-bit fault.
214 StoreElement(two_byte_result,
215 AccessBuilderTS::ForSeqTwoByteStringCharacter(),
216 var_max_index, code16);
217 var_max_index = WordPtrAdd(var_max_index, 1);
218
219 // Resume copying the passed-in arguments from the same place where the
220 // 8-bit copy stopped, but this time copying over all of the characters
221 // using a 16-bit representation.
222 FOREACH(arg, arguments.Range(var_max_index)) {
223 V<Word32> code32 = TruncateTaggedToWord32(context, arg);
224 V<Word32> code16 =
225 Word32BitwiseAnd(code32, String::kMaxUtf16CodeUnit);
226
227 StoreElement(two_byte_result,
228 AccessBuilderTS::ForSeqTwoByteStringCharacter(),
229 var_max_index, code16);
230 var_max_index = WordPtrAdd(var_max_index, 1);
231 }
232 PopAndReturn(arguments, two_byte_result);
233 }
234
235 // The {code16} fits into the SeqOneByteString {one_byte_result}.
236 StoreElement(one_byte_result,
237 AccessBuilderTS::ForSeqOneByteStringCharacter(),
238 var_max_index, code16);
239 var_max_index = WordPtrAdd(var_max_index, 1);
240 }
241 PopAndReturn(arguments, one_byte_result);
242 }
243}
244
245#endif // V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
246
248
249} // namespace v8::internal
#define BIND(label)
#define ELSE
#define GOTO(label,...)
#define UNLIKELY(...)
#define TSA_DCHECK(assembler, condition)
#define FOREACH(...)
#define IF(...)
#define GOTO_IF(cond, label,...)
#define TS_BUILTIN(Name, BaseAssembler)
static constexpr int kEmptyHashField
Definition name.h:133
StringBuiltinsAssemblerTS(compiler::turboshaft::PipelineData *data, compiler::turboshaft::Graph &graph, Zone *phase_zone)
V< SeqOneByteString > AllocateSeqOneByteString(V< WordPtr > length)
void CopyStringCharacters(V< String > src_string, ConstOrV< WordPtr > src_begin, String::Encoding src_encoding, V< String > dst_string, ConstOrV< WordPtr > dst_begin, String::Encoding dst_encoding, ConstOrV< WordPtr > character_count)
V< SeqTwoByteString > AllocateSeqTwoByteString(V< WordPtr > length)
static const int32_t kMaxOneByteCharCode
Definition string.h:500
static const int kMaxUtf16CodeUnit
Definition string.h:502
Map ForMap(WriteBarrierKind write_barrier=kMapWriteBarrier)
static constexpr MemoryRepresentation TaggedSigned()
static constexpr MemoryRepresentation Uint16()
static constexpr MemoryRepresentation Uint8()
TNode< Object > receiver
ZoneVector< RpoNumber > & result
int position
Definition liveedit.cc:290
Zip(Iterables... iterables) -> Zip< Iterables... >
std::conditional_t< Is64(), Word64, Word32 > WordPtr
Definition index.h:225
Sequence(V< T >, V< T >) -> Sequence< T >
constexpr intptr_t kObjectAlignment
Definition globals.h:930
const int kHeapObjectTag
Definition v8-internal.h:72
V8_EXPORT_PRIVATE FlagValues v8_flags
#define OFFSET_OF_DATA_START(Type)
#define BUILTIN_REDUCER(name)