v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-intl-gen.cc
Go to the documentation of this file.
1// Copyright 2017 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTL_SUPPORT
6#error Internationalization is expected to be enabled.
7#endif // V8_INTL_SUPPORT
8
15#include "src/objects/objects.h"
16
17namespace v8 {
18namespace internal {
19
21
23 public:
26
28 Runtime::FunctionId format_func_id,
29 const char* method_name);
30
32
42
44 size_t effective_offset = OFFSET_OF_DATA_START(SeqOneByteString) +
45 sizeof(SeqOneByteString::Char) * index -
47 return Load<Uint8T>(seq_string, IntPtrConstant(effective_offset));
48 }
49
50 // Jumps to {target} if the first two characters of {seq_string} equal
51 // {pattern} ignoring case.
53 const char* pattern, Label* target) {
54 size_t effective_offset =
56 TNode<Uint16T> raw =
57 Load<Uint16T>(seq_string, IntPtrConstant(effective_offset));
58 DCHECK_EQ(strlen(pattern), 2);
59#if V8_TARGET_BIG_ENDIAN
60 int raw_pattern = (pattern[0] << 8) + pattern[1];
61#else
62 int raw_pattern = pattern[0] + (pattern[1] << 8);
63#endif
65 Int32Constant(raw_pattern)),
66 target);
67 }
68
70 return Uint32GreaterThan(
72 Int32Constant('z' - 'a'));
73 }
74
79 void ToLowerCaseImpl(TNode<String> string, TNode<Object> maybe_locales,
81 std::function<void(TNode<JSAny>)> ReturnFct);
82};
83
84TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
85 const auto string = Parameter<String>(Descriptor::kString);
86 ToLowerCaseImpl(string, TNode<Object>() /*maybe_locales*/, TNode<Context>(),
87 ToLowerCaseKind::kToLowerCase,
88 [this](TNode<Object> ret) { Return(ret); });
89}
90
91TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
92 auto maybe_string = Parameter<Object>(Descriptor::kReceiver);
93 auto context = Parameter<Context>(Descriptor::kContext);
94
95 TNode<String> string =
96 ToThisString(context, maybe_string, "String.prototype.toLowerCase");
97
98 Return(CallBuiltin(Builtin::kStringToLowerCaseIntl, context, string));
99}
100
101TF_BUILTIN(StringPrototypeToLocaleLowerCase, IntlBuiltinsAssembler) {
102 TNode<Int32T> argc =
103 UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount);
104 CodeStubArguments args(this, argc);
105 TNode<Object> maybe_string = args.GetReceiver();
106 TNode<Context> context = Parameter<Context>(Descriptor::kContext);
107 TNode<Object> maybe_locales = args.GetOptionalArgumentValue(0);
108 TNode<String> string =
109 ToThisString(context, maybe_string, "String.prototype.toLocaleLowerCase");
110 ToLowerCaseImpl(string, maybe_locales, context,
111 ToLowerCaseKind::kToLocaleLowerCase,
112 [&args](TNode<JSAny> ret) { args.PopAndReturn(ret); });
113}
114
116 TNode<String> string, TNode<Object> maybe_locales, TNode<Context> context,
117 ToLowerCaseKind kind, std::function<void(TNode<JSAny>)> ReturnFct) {
118 Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
119
120 // Unpack strings if possible, and bail to runtime unless we get a one-byte
121 // flat string.
122 ToDirectStringAssembler to_direct(
124 to_direct.TryToDirect(&runtime);
125
127 Label fast(this), check_locale(this);
128 // Check for fast locales.
129 GotoIf(IsUndefined(maybe_locales), &fast);
130 // Passing a Smi as locales requires performing a ToObject conversion
131 // followed by reading the length property and the "indexed" properties of
132 // it until a valid locale is found.
133 GotoIf(TaggedIsSmi(maybe_locales), &runtime);
134 GotoIfNot(IsString(CAST(maybe_locales)), &runtime);
135 GotoIfNot(IsSeqOneByteString(CAST(maybe_locales)), &runtime);
136 TNode<SeqOneByteString> locale = CAST(maybe_locales);
137 TNode<Uint32T> locale_length = LoadStringLengthAsWord32(locale);
138 GotoIf(Int32LessThan(locale_length, Int32Constant(2)), &runtime);
139 GotoIf(IsNonAlpha(GetChar(locale, 0)), &runtime);
140 GotoIf(IsNonAlpha(GetChar(locale, 1)), &runtime);
141 GotoIf(Word32Equal(locale_length, Int32Constant(2)), &check_locale);
142 GotoIf(Word32NotEqual(locale_length, Int32Constant(5)), &runtime);
143 GotoIf(Word32NotEqual(GetChar(locale, 2), Int32Constant('-')), &runtime);
144 GotoIf(IsNonAlpha(GetChar(locale, 3)), &runtime);
145 GotoIf(IsNonAlpha(GetChar(locale, 4)), &runtime);
146 Goto(&check_locale);
147
148 Bind(&check_locale);
149 JumpIfStartsWithIgnoreCase(locale, "az", &runtime);
150 JumpIfStartsWithIgnoreCase(locale, "el", &runtime);
151 JumpIfStartsWithIgnoreCase(locale, "lt", &runtime);
152 JumpIfStartsWithIgnoreCase(locale, "tr", &runtime);
153 Goto(&fast);
154
155 Bind(&fast);
156 }
157
158 // Early exit on empty string.
159 const TNode<Uint32T> length = LoadStringLengthAsWord32(string);
160 GotoIf(Word32Equal(length, Uint32Constant(0)), &return_string);
161
162 const TNode<BoolT> is_one_byte = to_direct.IsOneByte();
163 GotoIfNot(is_one_byte, &runtime);
164
165 // For short strings, do the conversion in CSA through the lookup table.
166
167 const TNode<String> dst = AllocateSeqOneByteString(length);
168
169 const int kMaxShortStringLength = 24; // Determined empirically.
170 GotoIf(Uint32GreaterThan(length, Uint32Constant(kMaxShortStringLength)),
171 &call_c);
172
173 {
174 const TNode<IntPtrT> dst_ptr = PointerToSeqStringData(dst);
175 TVARIABLE(IntPtrT, var_cursor, IntPtrConstant(0));
176
177 const TNode<IntPtrT> start_address =
178 ReinterpretCast<IntPtrT>(to_direct.PointerToData(&call_c));
179 const TNode<IntPtrT> end_address =
180 Signed(IntPtrAdd(start_address, ChangeUint32ToWord(length)));
181
182 const TNode<ExternalReference> to_lower_table_addr =
183 ExternalConstant(ExternalReference::intl_to_latin1_lower_table());
184
185 TVARIABLE(Word32T, var_did_change, Int32Constant(0));
186
187 VariableList push_vars({&var_cursor, &var_did_change}, zone());
189 push_vars, start_address, end_address,
190 [&](TNode<IntPtrT> current) {
191 TNode<Uint8T> c = Load<Uint8T>(current);
192 TNode<Uint8T> lower =
193 Load<Uint8T>(to_lower_table_addr, ChangeInt32ToIntPtr(c));
195 var_cursor.value(), lower);
196
197 var_did_change =
198 Word32Or(Word32NotEqual(c, lower), var_did_change.value());
199
200 Increment(&var_cursor);
201 },
203
204 // Return the original string if it remained unchanged in order to preserve
205 // e.g. internalization and private symbols (such as the preserved object
206 // hash) on the source string.
207 GotoIfNot(var_did_change.value(), &return_string);
208
209 ReturnFct(dst);
210 }
211
212 // Call into C for case conversion. The signature is:
213 // String ConvertOneByteToLower(String src, String dst);
214 BIND(&call_c);
215 {
216 const TNode<String> src = to_direct.string();
217
218 const TNode<ExternalReference> function_addr =
219 ExternalConstant(ExternalReference::intl_convert_one_byte_to_lower());
220
221 MachineType type_tagged = MachineType::AnyTagged();
222
224 function_addr, type_tagged, std::make_pair(type_tagged, src),
225 std::make_pair(type_tagged, dst)));
226
227 ReturnFct(result);
228 }
229
230 BIND(&return_string);
231 ReturnFct(string);
232
233 BIND(&runtime);
235 ReturnFct(CallRuntime<JSAny>(Runtime::kStringToLocaleLowerCase, context,
236 string, maybe_locales));
237 } else {
239 ReturnFct(CallRuntime<JSAny>(Runtime::kStringToLowerCaseIntl,
240 NoContextConstant(), string));
241 }
242}
243
245 TNode<Int32T> argc,
246 Runtime::FunctionId format_func_id,
247 const char* method_name) {
248 CodeStubArguments args(this, argc);
249
250 // Label has_list(this);
251 // 1. Let lf be this value.
252 // 2. If Type(lf) is not Object, throw a TypeError exception.
253 TNode<Object> receiver = args.GetReceiver();
254
255 // 3. If lf does not have an [[InitializedListFormat]] internal slot, throw a
256 // TypeError exception.
257 ThrowIfNotInstanceType(context, receiver, JS_LIST_FORMAT_TYPE, method_name);
258 TNode<JSListFormat> list_format = CAST(receiver);
259
260 TNode<Object> list = args.GetOptionalArgumentValue(0);
261 {
262 // 4. Let stringList be ? StringListFromIterable(list).
263 TNode<Object> string_list =
264 CallBuiltin(Builtin::kStringListFromIterable, context, list);
265
266 // 6. Return ? FormatList(lf, stringList).
267 args.PopAndReturn(
268 CallRuntime<JSAny>(format_func_id, context, list_format, string_list));
269 }
270}
271
279
280TF_BUILTIN(ListFormatPrototypeFormat, IntlBuiltinsAssembler) {
281 ListFormatCommon(
282 Parameter<Context>(Descriptor::kContext),
283 UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount),
284 Runtime::kFormatList, "Intl.ListFormat.prototype.format");
285}
286
287TF_BUILTIN(ListFormatPrototypeFormatToParts, IntlBuiltinsAssembler) {
288 ListFormatCommon(
289 Parameter<Context>(Descriptor::kContext),
290 UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount),
291 Runtime::kFormatListToParts, "Intl.ListFormat.prototype.formatToParts");
292}
293
295
296} // namespace internal
297} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
#define TF_BUILTIN(Name, AssemblerBase)
Builtins::Kind kind
Definition builtins.cc:40
TNode< String > AllocateSeqOneByteString(uint32_t length, AllocationFlags flags=AllocationFlag::kNone)
TNode< JSArray > AllocateJSArray(ElementsKind kind, TNode< Map > array_map, TNode< IntPtrT > capacity, TNode< Smi > length, std::optional< TNode< AllocationSite > > allocation_site, AllocationFlags allocation_flags=AllocationFlag::kNone)
void ThrowIfNotInstanceType(TNode< Context > context, TNode< Object > value, InstanceType instance_type, char const *method_name)
void Increment(TVariable< TIndex > *variable, int value=1)
TNode< Map > LoadJSArrayElementsMap(ElementsKind kind, TNode< NativeContext > native_context)
void BuildFastLoop(const VariableList &vars, TVariable< TIndex > &var_index, TNode< TIndex > start_index, TNode< TIndex > end_index, const FastLoopBody< TIndex > &body, TNode< TIndex > increment, LoopUnrollingMode unrolling_mode, IndexAdvanceMode advance_mode, IndexAdvanceDirection advance_direction)
TNode< BoolT > IsSequentialStringInstanceType(TNode< Int32T > instance_type)
TNode< BoolT > IsSeqOneByteString(TNode< HeapObject > object)
TNode< Uint16T > LoadInstanceType(TNode< HeapObject > object)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
TNode< BoolT > TaggedIsSmi(TNode< MaybeObject > a)
TNode< BoolT > IsString(TNode< HeapObject > object)
TNode< Uint32T > LoadStringLengthAsWord32(TNode< String > string)
TNode< BoolT > IsNonAlpha(TNode< Uint8T > character)
TNode< IntPtrT > PointerToSeqStringData(TNode< String > seq_string)
void ListFormatCommon(TNode< Context > context, TNode< Int32T > argc, Runtime::FunctionId format_func_id, const char *method_name)
void ToLowerCaseImpl(TNode< String > string, TNode< Object > maybe_locales, TNode< Context > context, ToLowerCaseKind kind, std::function< void(TNode< JSAny >)> ReturnFct)
TNode< Uint8T > GetChar(TNode< SeqOneByteString > seq_string, int index)
IntlBuiltinsAssembler(compiler::CodeAssemblerState *state)
void JumpIfStartsWithIgnoreCase(TNode< SeqOneByteString > seq_string, const char *pattern, Label *target)
TNode< JSArray > AllocateEmptyJSArray(TNode< Context > context)
static constexpr MachineType AnyTagged()
TNode< String > TryToDirect(Label *if_bailout)
TNode< RawPtrT > PointerToData(Label *if_bailout)
TNode< BoolT > Word32NotEqual(TNode< Word32T > left, TNode< Word32T > right)
TNode< IntPtrT > IntPtrAdd(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< Int32T > Signed(TNode< Word32T > x)
TNode< IntPtrT > IntPtrConstant(intptr_t value)
TNode< UintPtrT > ChangeUint32ToWord(TNode< Word32T > value)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
TNode< T > ReinterpretCast(Node *value)
TNode< IntPtrT > BitcastTaggedToWord(TNode< Smi > node)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
Node * Load(MachineType type, Node *base)
TNode< IntPtrT > ChangeInt32ToIntPtr(TNode< Word32T > value)
TNode< Int32T > Int32Sub(TNode< Int32T > left, TNode< Int32T > right)
TNode< Int32T > Word32Or(TNode< Int32T > left, TNode< Int32T > right)
TNode< ExternalReference > ExternalConstant(ExternalReference address)
TNode< Int32T > Int32Constant(int32_t value)
Node * CallCFunction(Node *function, std::optional< MachineType > return_type, CArgs... cargs)
TNode< Uint32T > Uint32Constant(uint32_t value)
TNode< BoolT > Word32Equal(TNode< Word32T > left, TNode< Word32T > right)
TNode< T > CallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
void StoreNoWriteBarrier(MachineRepresentation rep, Node *base, Node *value)
#define CAST(x)
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
TNode< Object > receiver
std::string pattern
ZoneVector< RpoNumber > & result
constexpr int kCharSize
Definition globals.h:396
BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL int character
const int kHeapObjectTag
Definition v8-internal.h:72
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define OFFSET_OF_DATA_START(Type)