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
9 #include <cmath>
10 #include <list>
11 #include <memory>
12
13 #include "src/builtins/builtins-utils-inl.h"
14 #include "src/builtins/builtins.h"
15 #include "src/date/date.h"
16 #include "src/logging/counters.h"
17 #include "src/objects/elements.h"
18 #include "src/objects/intl-objects.h"
19 #include "src/objects/js-array-inl.h"
20 #include "src/objects/js-break-iterator-inl.h"
21 #include "src/objects/js-collator-inl.h"
22 #include "src/objects/js-date-time-format-inl.h"
23 #include "src/objects/js-display-names-inl.h"
24 #include "src/objects/js-list-format-inl.h"
25 #include "src/objects/js-locale-inl.h"
26 #include "src/objects/js-number-format-inl.h"
27 #include "src/objects/js-plural-rules-inl.h"
28 #include "src/objects/js-relative-time-format-inl.h"
29 #include "src/objects/js-segment-iterator-inl.h"
30 #include "src/objects/js-segmenter-inl.h"
31 #include "src/objects/js-segments-inl.h"
32 #include "src/objects/objects-inl.h"
33 #include "src/objects/option-utils.h"
34 #include "src/objects/property-descriptor.h"
35 #include "src/objects/smi.h"
36 #include "unicode/brkiter.h"
37
38 namespace v8 {
39 namespace internal {
40
BUILTIN(StringPrototypeToUpperCaseIntl)41 BUILTIN(StringPrototypeToUpperCaseIntl) {
42 HandleScope scope(isolate);
43 TO_THIS_STRING(string, "String.prototype.toUpperCase");
44 string = String::Flatten(isolate, string);
45 RETURN_RESULT_OR_FAILURE(isolate, Intl::ConvertToUpper(isolate, string));
46 }
47
BUILTIN(StringPrototypeNormalizeIntl)48 BUILTIN(StringPrototypeNormalizeIntl) {
49 HandleScope handle_scope(isolate);
50 isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringNormalize);
51 TO_THIS_STRING(string, "String.prototype.normalize");
52
53 Handle<Object> form_input = args.atOrUndefined(isolate, 1);
54
55 RETURN_RESULT_OR_FAILURE(isolate,
56 Intl::Normalize(isolate, string, form_input));
57 }
58
BUILTIN(V8BreakIteratorSupportedLocalesOf)59 BUILTIN(V8BreakIteratorSupportedLocalesOf) {
60 HandleScope scope(isolate);
61 Handle<Object> locales = args.atOrUndefined(isolate, 1);
62 Handle<Object> options = args.atOrUndefined(isolate, 2);
63
64 RETURN_RESULT_OR_FAILURE(
65 isolate, Intl::SupportedLocalesOf(
66 isolate, "Intl.v8BreakIterator.supportedLocalesOf",
67 JSV8BreakIterator::GetAvailableLocales(), locales, options));
68 }
69
BUILTIN(NumberFormatSupportedLocalesOf)70 BUILTIN(NumberFormatSupportedLocalesOf) {
71 HandleScope scope(isolate);
72 Handle<Object> locales = args.atOrUndefined(isolate, 1);
73 Handle<Object> options = args.atOrUndefined(isolate, 2);
74
75 RETURN_RESULT_OR_FAILURE(
76 isolate, Intl::SupportedLocalesOf(
77 isolate, "Intl.NumberFormat.supportedLocalesOf",
78 JSNumberFormat::GetAvailableLocales(), locales, options));
79 }
80
BUILTIN(NumberFormatPrototypeFormatToParts)81 BUILTIN(NumberFormatPrototypeFormatToParts) {
82 const char* const method_name = "Intl.NumberFormat.prototype.formatToParts";
83 HandleScope handle_scope(isolate);
84 CHECK_RECEIVER(JSNumberFormat, number_format, method_name);
85
86 Handle<Object> x;
87 if (args.length() >= 2) {
88 Handle<Object> value = args.at(1);
89 if (FLAG_harmony_intl_number_format_v3) {
90 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
91 isolate, x,
92 Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, value));
93 } else {
94 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
95 Object::ToNumeric(isolate, value));
96 }
97 } else {
98 x = isolate->factory()->nan_value();
99 }
100
101 RETURN_RESULT_OR_FAILURE(
102 isolate, JSNumberFormat::FormatToParts(isolate, number_format, x));
103 }
104
BUILTIN(DateTimeFormatPrototypeResolvedOptions)105 BUILTIN(DateTimeFormatPrototypeResolvedOptions) {
106 const char* const method_name =
107 "Intl.DateTimeFormat.prototype.resolvedOptions";
108 HandleScope scope(isolate);
109 CHECK_RECEIVER(JSReceiver, format_holder, method_name);
110
111 // 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
112 Handle<JSDateTimeFormat> date_time_format;
113 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
114 isolate, date_time_format,
115 JSDateTimeFormat::UnwrapDateTimeFormat(isolate, format_holder));
116
117 RETURN_RESULT_OR_FAILURE(
118 isolate, JSDateTimeFormat::ResolvedOptions(isolate, date_time_format));
119 }
120
BUILTIN(DateTimeFormatSupportedLocalesOf)121 BUILTIN(DateTimeFormatSupportedLocalesOf) {
122 HandleScope scope(isolate);
123 Handle<Object> locales = args.atOrUndefined(isolate, 1);
124 Handle<Object> options = args.atOrUndefined(isolate, 2);
125
126 RETURN_RESULT_OR_FAILURE(
127 isolate, Intl::SupportedLocalesOf(
128 isolate, "Intl.DateTimeFormat.supportedLocalesOf",
129 JSDateTimeFormat::GetAvailableLocales(), locales, options));
130 }
131
BUILTIN(DateTimeFormatPrototypeFormatToParts)132 BUILTIN(DateTimeFormatPrototypeFormatToParts) {
133 const char* const method_name = "Intl.DateTimeFormat.prototype.formatToParts";
134 HandleScope handle_scope(isolate);
135 CHECK_RECEIVER(JSObject, date_format_holder, method_name);
136 Factory* factory = isolate->factory();
137
138 if (!date_format_holder->IsJSDateTimeFormat()) {
139 THROW_NEW_ERROR_RETURN_FAILURE(
140 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
141 factory->NewStringFromAsciiChecked(method_name),
142 date_format_holder));
143 }
144 Handle<JSDateTimeFormat> dtf =
145 Handle<JSDateTimeFormat>::cast(date_format_holder);
146
147 Handle<Object> x = args.atOrUndefined(isolate, 1);
148 if (x->IsUndefined(isolate)) {
149 x = factory->NewNumber(JSDate::CurrentTimeValue(isolate));
150 } else {
151 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
152 Object::ToNumber(isolate, args.at(1)));
153 }
154
155 double date_value = DateCache::TimeClip(x->Number());
156 if (std::isnan(date_value)) {
157 THROW_NEW_ERROR_RETURN_FAILURE(
158 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
159 }
160
161 RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::FormatToParts(
162 isolate, dtf, date_value, false));
163 }
164
165 // Common code for DateTimeFormatPrototypeFormtRange(|ToParts)
166 template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSDateTimeFormat>,
167 double, double)>
DateTimeFormatRange(BuiltinArguments args,Isolate * isolate,const char * const method_name)168 V8_WARN_UNUSED_RESULT Object DateTimeFormatRange(
169 BuiltinArguments args, Isolate* isolate, const char* const method_name) {
170 // 1. Let dtf be this value.
171 // 2. If Type(dtf) is not Object, throw a TypeError exception.
172 CHECK_RECEIVER(JSObject, date_format_holder, method_name);
173
174 Factory* factory = isolate->factory();
175
176 // 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot,
177 // throw a TypeError exception.
178 if (!date_format_holder->IsJSDateTimeFormat()) {
179 THROW_NEW_ERROR_RETURN_FAILURE(
180 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
181 factory->NewStringFromAsciiChecked(method_name),
182 date_format_holder));
183 }
184 Handle<JSDateTimeFormat> dtf =
185 Handle<JSDateTimeFormat>::cast(date_format_holder);
186
187 // 4. If startDate is undefined or endDate is undefined, throw a TypeError
188 // exception.
189 Handle<Object> start_date = args.atOrUndefined(isolate, 1);
190 Handle<Object> end_date = args.atOrUndefined(isolate, 2);
191 if (start_date->IsUndefined(isolate) || end_date->IsUndefined(isolate)) {
192 THROW_NEW_ERROR_RETURN_FAILURE(
193 isolate, NewTypeError(MessageTemplate::kInvalidTimeValue));
194 }
195 // 5. Let x be ? ToNumber(startDate).
196 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, start_date,
197 Object::ToNumber(isolate, start_date));
198 double x = start_date->Number();
199
200 // 6. Let y be ? ToNumber(endDate).
201 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, end_date,
202 Object::ToNumber(isolate, end_date));
203 double y = end_date->Number();
204 // 7. If x is greater than y, throw a RangeError exception.
205 if (x > y) {
206 THROW_NEW_ERROR_RETURN_FAILURE(
207 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
208 }
209
210 // 8. Return ? FormatDateTimeRange(dtf, x, y)
211 // OR
212 // 8. Return ? FormatDateTimeRangeToParts(dtf, x, y).
213 RETURN_RESULT_OR_FAILURE(isolate, F(isolate, dtf, x, y));
214 }
215
BUILTIN(DateTimeFormatPrototypeFormatRange)216 BUILTIN(DateTimeFormatPrototypeFormatRange) {
217 const char* const method_name = "Intl.DateTimeFormat.prototype.formatRange";
218 HandleScope handle_scope(isolate);
219 return DateTimeFormatRange<String, JSDateTimeFormat::FormatRange>(
220 args, isolate, method_name);
221 }
222
BUILTIN(DateTimeFormatPrototypeFormatRangeToParts)223 BUILTIN(DateTimeFormatPrototypeFormatRangeToParts) {
224 const char* const method_name =
225 "Intl.DateTimeFormat.prototype.formatRangeToParts";
226 HandleScope handle_scope(isolate);
227 return DateTimeFormatRange<JSArray, JSDateTimeFormat::FormatRangeToParts>(
228 args, isolate, method_name);
229 }
230
231 namespace {
232
CreateBoundFunction(Isolate * isolate,Handle<JSObject> object,Builtin builtin,int len)233 Handle<JSFunction> CreateBoundFunction(Isolate* isolate,
234 Handle<JSObject> object, Builtin builtin,
235 int len) {
236 Handle<NativeContext> native_context(isolate->context().native_context(),
237 isolate);
238 Handle<Context> context = isolate->factory()->NewBuiltinContext(
239 native_context,
240 static_cast<int>(Intl::BoundFunctionContextSlot::kLength));
241
242 context->set(static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction),
243 *object);
244
245 Handle<SharedFunctionInfo> info =
246 isolate->factory()->NewSharedFunctionInfoForBuiltin(
247 isolate->factory()->empty_string(), builtin,
248 FunctionKind::kNormalFunction);
249 info->set_internal_formal_parameter_count(JSParameterCount(len));
250 info->set_length(len);
251
252 return Factory::JSFunctionBuilder{isolate, info, context}
253 .set_map(isolate->strict_function_without_prototype_map())
254 .Build();
255 }
256
257 /**
258 * Common code shared between DateTimeFormatConstructor and
259 * NumberFormatConstrutor
260 */
261 template <class T>
LegacyFormatConstructor(BuiltinArguments args,Isolate * isolate,v8::Isolate::UseCounterFeature feature,Handle<Object> constructor,const char * method_name)262 Object LegacyFormatConstructor(BuiltinArguments args, Isolate* isolate,
263 v8::Isolate::UseCounterFeature feature,
264 Handle<Object> constructor,
265 const char* method_name) {
266 isolate->CountUsage(feature);
267 Handle<JSReceiver> new_target;
268 // 1. If NewTarget is undefined, let newTarget be the active
269 // function object, else let newTarget be NewTarget.
270 if (args.new_target()->IsUndefined(isolate)) {
271 new_target = args.target();
272 } else {
273 new_target = Handle<JSReceiver>::cast(args.new_target());
274 }
275
276 // [[Construct]]
277 Handle<JSFunction> target = args.target();
278 Handle<Object> locales = args.atOrUndefined(isolate, 1);
279 Handle<Object> options = args.atOrUndefined(isolate, 2);
280
281 // 2. Let format be ? OrdinaryCreateFromConstructor(newTarget,
282 // "%<T>Prototype%", ...).
283 Handle<Map> map;
284 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
285 isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
286
287 // 3. Perform ? Initialize<T>(Format, locales, options).
288 Handle<T> format;
289 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
290 isolate, format, T::New(isolate, map, locales, options, method_name));
291 // 4. Let this be the this value.
292 if (args.new_target()->IsUndefined(isolate)) {
293 Handle<Object> receiver = args.receiver();
294 // 5. If NewTarget is undefined and ? OrdinaryHasInstance(%<T>%, this)
295 // is true, then Look up the intrinsic value that has been stored on
296 // the context.
297 Handle<Object> ordinary_has_instance_obj;
298 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
299 isolate, ordinary_has_instance_obj,
300 Object::OrdinaryHasInstance(isolate, constructor, receiver));
301 if (ordinary_has_instance_obj->BooleanValue(isolate)) {
302 if (!receiver->IsJSReceiver()) {
303 THROW_NEW_ERROR_RETURN_FAILURE(
304 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
305 isolate->factory()->NewStringFromAsciiChecked(
306 method_name),
307 receiver));
308 }
309 Handle<JSReceiver> rec = Handle<JSReceiver>::cast(receiver);
310 // a. Perform ? DefinePropertyOrThrow(this,
311 // %Intl%.[[FallbackSymbol]], PropertyDescriptor{ [[Value]]: format,
312 // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }).
313 PropertyDescriptor desc;
314 desc.set_value(format);
315 desc.set_writable(false);
316 desc.set_enumerable(false);
317 desc.set_configurable(false);
318 Maybe<bool> success = JSReceiver::DefineOwnProperty(
319 isolate, rec, isolate->factory()->intl_fallback_symbol(), &desc,
320 Just(kThrowOnError));
321 MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
322 CHECK(success.FromJust());
323 // b. b. Return this.
324 return *receiver;
325 }
326 }
327 // 6. Return format.
328 return *format;
329 }
330
331 /**
332 * Common code shared by ListFormat, RelativeTimeFormat, PluralRules, and
333 * Segmenter
334 */
335 template <class T>
DisallowCallConstructor(BuiltinArguments args,Isolate * isolate,v8::Isolate::UseCounterFeature feature,const char * method_name)336 Object DisallowCallConstructor(BuiltinArguments args, Isolate* isolate,
337 v8::Isolate::UseCounterFeature feature,
338 const char* method_name) {
339 isolate->CountUsage(feature);
340
341 // 1. If NewTarget is undefined, throw a TypeError exception.
342 if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
343 THROW_NEW_ERROR_RETURN_FAILURE(
344 isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
345 isolate->factory()->NewStringFromAsciiChecked(
346 method_name)));
347 }
348 // [[Construct]]
349 Handle<JSFunction> target = args.target();
350 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
351
352 Handle<Map> map;
353 // 2. Let result be OrdinaryCreateFromConstructor(NewTarget,
354 // "%<T>Prototype%").
355 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
356 isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
357
358 Handle<Object> locales = args.atOrUndefined(isolate, 1);
359 Handle<Object> options = args.atOrUndefined(isolate, 2);
360
361 // 3. Return New<T>(t, locales, options).
362 RETURN_RESULT_OR_FAILURE(isolate, T::New(isolate, map, locales, options));
363 }
364
365 /**
366 * Common code shared by Collator and V8BreakIterator
367 */
368 template <class T>
CallOrConstructConstructor(BuiltinArguments args,Isolate * isolate,const char * method_name)369 Object CallOrConstructConstructor(BuiltinArguments args, Isolate* isolate,
370 const char* method_name) {
371 Handle<JSReceiver> new_target;
372
373 if (args.new_target()->IsUndefined(isolate)) {
374 new_target = args.target();
375 } else {
376 new_target = Handle<JSReceiver>::cast(args.new_target());
377 }
378
379 // [[Construct]]
380 Handle<JSFunction> target = args.target();
381
382 Handle<Object> locales = args.atOrUndefined(isolate, 1);
383 Handle<Object> options = args.atOrUndefined(isolate, 2);
384
385 Handle<Map> map;
386 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
387 isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
388
389 RETURN_RESULT_OR_FAILURE(isolate,
390 T::New(isolate, map, locales, options, method_name));
391 }
392
393 } // namespace
394
395 // Intl.DisplayNames
396
BUILTIN(DisplayNamesConstructor)397 BUILTIN(DisplayNamesConstructor) {
398 HandleScope scope(isolate);
399
400 return DisallowCallConstructor<JSDisplayNames>(
401 args, isolate, v8::Isolate::UseCounterFeature::kDisplayNames,
402 "Intl.DisplayNames");
403 }
404
BUILTIN(DisplayNamesPrototypeResolvedOptions)405 BUILTIN(DisplayNamesPrototypeResolvedOptions) {
406 HandleScope scope(isolate);
407 CHECK_RECEIVER(JSDisplayNames, holder,
408 "Intl.DisplayNames.prototype.resolvedOptions");
409 return *JSDisplayNames::ResolvedOptions(isolate, holder);
410 }
411
BUILTIN(DisplayNamesSupportedLocalesOf)412 BUILTIN(DisplayNamesSupportedLocalesOf) {
413 HandleScope scope(isolate);
414 Handle<Object> locales = args.atOrUndefined(isolate, 1);
415 Handle<Object> options = args.atOrUndefined(isolate, 2);
416
417 RETURN_RESULT_OR_FAILURE(
418 isolate, Intl::SupportedLocalesOf(
419 isolate, "Intl.DisplayNames.supportedLocalesOf",
420 JSDisplayNames::GetAvailableLocales(), locales, options));
421 }
422
BUILTIN(DisplayNamesPrototypeOf)423 BUILTIN(DisplayNamesPrototypeOf) {
424 HandleScope scope(isolate);
425 CHECK_RECEIVER(JSDisplayNames, holder, "Intl.DisplayNames.prototype.of");
426 Handle<Object> code_obj = args.atOrUndefined(isolate, 1);
427
428 RETURN_RESULT_OR_FAILURE(isolate,
429 JSDisplayNames::Of(isolate, holder, code_obj));
430 }
431
432 // Intl.NumberFormat
433
BUILTIN(NumberFormatConstructor)434 BUILTIN(NumberFormatConstructor) {
435 HandleScope scope(isolate);
436
437 return LegacyFormatConstructor<JSNumberFormat>(
438 args, isolate, v8::Isolate::UseCounterFeature::kNumberFormat,
439 isolate->intl_number_format_function(), "Intl.NumberFormat");
440 }
441
BUILTIN(NumberFormatPrototypeResolvedOptions)442 BUILTIN(NumberFormatPrototypeResolvedOptions) {
443 HandleScope scope(isolate);
444 const char* const method_name = "Intl.NumberFormat.prototype.resolvedOptions";
445
446 // 1. Let nf be the this value.
447 // 2. If Type(nf) is not Object, throw a TypeError exception.
448 CHECK_RECEIVER(JSReceiver, number_format_holder, method_name);
449
450 // 3. Let nf be ? UnwrapNumberFormat(nf)
451 Handle<JSNumberFormat> number_format;
452 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
453 isolate, number_format,
454 JSNumberFormat::UnwrapNumberFormat(isolate, number_format_holder));
455
456 return *JSNumberFormat::ResolvedOptions(isolate, number_format);
457 }
458
BUILTIN(NumberFormatPrototypeFormatNumber)459 BUILTIN(NumberFormatPrototypeFormatNumber) {
460 const char* const method_name = "get Intl.NumberFormat.prototype.format";
461 HandleScope scope(isolate);
462
463 // 1. Let nf be the this value.
464 // 2. If Type(nf) is not Object, throw a TypeError exception.
465 CHECK_RECEIVER(JSReceiver, receiver, method_name);
466
467 // 3. Let nf be ? UnwrapNumberFormat(nf).
468 Handle<JSNumberFormat> number_format;
469 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
470 isolate, number_format,
471 JSNumberFormat::UnwrapNumberFormat(isolate, receiver));
472
473 Handle<Object> bound_format(number_format->bound_format(), isolate);
474
475 // 4. If nf.[[BoundFormat]] is undefined, then
476 if (!bound_format->IsUndefined(isolate)) {
477 DCHECK(bound_format->IsJSFunction());
478 // 5. Return nf.[[BoundFormat]].
479 return *bound_format;
480 }
481
482 Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
483 isolate, number_format, Builtin::kNumberFormatInternalFormatNumber, 1);
484
485 // 4. c. Set nf.[[BoundFormat]] to F.
486 number_format->set_bound_format(*new_bound_format_function);
487
488 // 5. Return nf.[[BoundFormat]].
489 return *new_bound_format_function;
490 }
491
BUILTIN(NumberFormatInternalFormatNumber)492 BUILTIN(NumberFormatInternalFormatNumber) {
493 HandleScope scope(isolate);
494
495 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
496
497 // 1. Let nf be F.[[NumberFormat]].
498 // 2. Assert: Type(nf) is Object and nf has an
499 // [[InitializedNumberFormat]] internal slot.
500 Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>(
501 JSNumberFormat::cast(context->get(
502 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
503 isolate);
504
505 // 3. If value is not provided, let value be undefined.
506 Handle<Object> value = args.atOrUndefined(isolate, 1);
507
508 // 4. Let x be ? ToNumeric(value).
509 Handle<Object> numeric_obj;
510 if (FLAG_harmony_intl_number_format_v3) {
511 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
512 isolate, numeric_obj,
513 Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, value));
514 } else {
515 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, numeric_obj,
516 Object::ToNumeric(isolate, value));
517 }
518
519 icu::number::LocalizedNumberFormatter* icu_localized_number_formatter =
520 number_format->icu_number_formatter().raw();
521 CHECK_NOT_NULL(icu_localized_number_formatter);
522
523 // Return FormatNumber(nf, x).
524 RETURN_RESULT_OR_FAILURE(
525 isolate, JSNumberFormat::FormatNumeric(
526 isolate, *icu_localized_number_formatter, numeric_obj));
527 }
528
529 // Common code for NumberFormatPrototypeFormtRange(|ToParts)
530 template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSNumberFormat>,
531 Handle<Object>, Handle<Object>)>
NumberFormatRange(BuiltinArguments args,Isolate * isolate,const char * const method_name)532 V8_WARN_UNUSED_RESULT Object NumberFormatRange(BuiltinArguments args,
533 Isolate* isolate,
534 const char* const method_name) {
535 // 1. Let nf be this value.
536 // 2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
537 CHECK_RECEIVER(JSNumberFormat, nf, method_name);
538
539 Handle<Object> start = args.atOrUndefined(isolate, 1);
540 Handle<Object> end = args.atOrUndefined(isolate, 2);
541
542 Factory* factory = isolate->factory();
543 // 3. If start is undefined or end is undefined, throw a TypeError exception.
544 if (start->IsUndefined(isolate)) {
545 THROW_NEW_ERROR_RETURN_FAILURE(
546 isolate,
547 NewTypeError(MessageTemplate::kInvalid,
548 factory->NewStringFromStaticChars("start"), start));
549 }
550 if (end->IsUndefined(isolate)) {
551 THROW_NEW_ERROR_RETURN_FAILURE(
552 isolate, NewTypeError(MessageTemplate::kInvalid,
553 factory->NewStringFromStaticChars("end"), end));
554 }
555
556 // 4. Let x be ? ToIntlMathematicalValue(start).
557 Handle<Object> x;
558 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
559 isolate, x,
560 Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, start));
561
562 // 5. Let y be ? ToIntlMathematicalValue(end).
563 Handle<Object> y;
564 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
565 isolate, y,
566 Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, end));
567
568 RETURN_RESULT_OR_FAILURE(isolate, F(isolate, nf, x, y));
569 }
570
BUILTIN(NumberFormatPrototypeFormatRange)571 BUILTIN(NumberFormatPrototypeFormatRange) {
572 const char* const method_name = "Intl.NumberFormat.prototype.formatRange";
573 HandleScope handle_scope(isolate);
574 return NumberFormatRange<String, JSNumberFormat::FormatNumericRange>(
575 args, isolate, method_name);
576 }
577
BUILTIN(NumberFormatPrototypeFormatRangeToParts)578 BUILTIN(NumberFormatPrototypeFormatRangeToParts) {
579 const char* const method_name =
580 "Intl.NumberFormat.prototype.formatRangeToParts";
581 HandleScope handle_scope(isolate);
582 return NumberFormatRange<JSArray, JSNumberFormat::FormatNumericRangeToParts>(
583 args, isolate, method_name);
584 }
585
BUILTIN(DateTimeFormatConstructor)586 BUILTIN(DateTimeFormatConstructor) {
587 HandleScope scope(isolate);
588
589 return LegacyFormatConstructor<JSDateTimeFormat>(
590 args, isolate, v8::Isolate::UseCounterFeature::kDateTimeFormat,
591 isolate->intl_date_time_format_function(), "Intl.DateTimeFormat");
592 }
593
BUILTIN(DateTimeFormatPrototypeFormat)594 BUILTIN(DateTimeFormatPrototypeFormat) {
595 const char* const method_name = "get Intl.DateTimeFormat.prototype.format";
596 HandleScope scope(isolate);
597
598 // 1. Let dtf be this value.
599 // 2. If Type(dtf) is not Object, throw a TypeError exception.
600 CHECK_RECEIVER(JSReceiver, receiver, method_name);
601
602 // 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
603 Handle<JSDateTimeFormat> format;
604 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
605 isolate, format,
606 JSDateTimeFormat::UnwrapDateTimeFormat(isolate, receiver));
607
608 Handle<Object> bound_format = Handle<Object>(format->bound_format(), isolate);
609
610 // 4. If dtf.[[BoundFormat]] is undefined, then
611 if (!bound_format->IsUndefined(isolate)) {
612 DCHECK(bound_format->IsJSFunction());
613 // 5. Return dtf.[[BoundFormat]].
614 return *bound_format;
615 }
616
617 Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
618 isolate, format, Builtin::kDateTimeFormatInternalFormat, 1);
619
620 // 4.c. Set dtf.[[BoundFormat]] to F.
621 format->set_bound_format(*new_bound_format_function);
622
623 // 5. Return dtf.[[BoundFormat]].
624 return *new_bound_format_function;
625 }
626
BUILTIN(DateTimeFormatInternalFormat)627 BUILTIN(DateTimeFormatInternalFormat) {
628 HandleScope scope(isolate);
629 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
630
631 // 1. Let dtf be F.[[DateTimeFormat]].
632 // 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
633 // internal slot.
634 Handle<JSDateTimeFormat> date_format_holder = Handle<JSDateTimeFormat>(
635 JSDateTimeFormat::cast(context->get(
636 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
637 isolate);
638
639 Handle<Object> date = args.atOrUndefined(isolate, 1);
640
641 RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::DateTimeFormat(
642 isolate, date_format_holder, date));
643 }
644
BUILTIN(IntlGetCanonicalLocales)645 BUILTIN(IntlGetCanonicalLocales) {
646 HandleScope scope(isolate);
647 Handle<Object> locales = args.atOrUndefined(isolate, 1);
648
649 RETURN_RESULT_OR_FAILURE(isolate,
650 Intl::GetCanonicalLocales(isolate, locales));
651 }
652
BUILTIN(IntlSupportedValuesOf)653 BUILTIN(IntlSupportedValuesOf) {
654 HandleScope scope(isolate);
655 Handle<Object> locales = args.atOrUndefined(isolate, 1);
656
657 RETURN_RESULT_OR_FAILURE(isolate, Intl::SupportedValuesOf(isolate, locales));
658 }
659
BUILTIN(ListFormatConstructor)660 BUILTIN(ListFormatConstructor) {
661 HandleScope scope(isolate);
662
663 return DisallowCallConstructor<JSListFormat>(
664 args, isolate, v8::Isolate::UseCounterFeature::kListFormat,
665 "Intl.ListFormat");
666 }
667
BUILTIN(ListFormatPrototypeResolvedOptions)668 BUILTIN(ListFormatPrototypeResolvedOptions) {
669 HandleScope scope(isolate);
670 CHECK_RECEIVER(JSListFormat, format_holder,
671 "Intl.ListFormat.prototype.resolvedOptions");
672 return *JSListFormat::ResolvedOptions(isolate, format_holder);
673 }
674
BUILTIN(ListFormatSupportedLocalesOf)675 BUILTIN(ListFormatSupportedLocalesOf) {
676 HandleScope scope(isolate);
677 Handle<Object> locales = args.atOrUndefined(isolate, 1);
678 Handle<Object> options = args.atOrUndefined(isolate, 2);
679
680 RETURN_RESULT_OR_FAILURE(
681 isolate, Intl::SupportedLocalesOf(
682 isolate, "Intl.ListFormat.supportedLocalesOf",
683 JSListFormat::GetAvailableLocales(), locales, options));
684 }
685
686 // Intl.Locale implementation
BUILTIN(LocaleConstructor)687 BUILTIN(LocaleConstructor) {
688 HandleScope scope(isolate);
689
690 isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale);
691
692 const char* method_name = "Intl.Locale";
693 if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
694 THROW_NEW_ERROR_RETURN_FAILURE(
695 isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
696 isolate->factory()->NewStringFromAsciiChecked(
697 method_name)));
698 }
699 // [[Construct]]
700 Handle<JSFunction> target = args.target();
701 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
702
703 Handle<Object> tag = args.atOrUndefined(isolate, 1);
704 Handle<Object> options = args.atOrUndefined(isolate, 2);
705
706 Handle<Map> map;
707 // 6. Let locale be ? OrdinaryCreateFromConstructor(NewTarget,
708 // %LocalePrototype%, internalSlotsList).
709 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
710 isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
711
712 // 7. If Type(tag) is not String or Object, throw a TypeError exception.
713 if (!tag->IsString() && !tag->IsJSReceiver()) {
714 THROW_NEW_ERROR_RETURN_FAILURE(
715 isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty));
716 }
717
718 Handle<String> locale_string;
719 // 8. If Type(tag) is Object and tag has an [[InitializedLocale]] internal
720 // slot, then
721 if (tag->IsJSLocale()) {
722 // a. Let tag be tag.[[Locale]].
723 locale_string = JSLocale::ToString(isolate, Handle<JSLocale>::cast(tag));
724 } else { // 9. Else,
725 // a. Let tag be ? ToString(tag).
726 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_string,
727 Object::ToString(isolate, tag));
728 }
729
730 // 10. Set options to ? CoerceOptionsToObject(options).
731 Handle<JSReceiver> options_object;
732 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
733 isolate, options_object,
734 CoerceOptionsToObject(isolate, options, method_name));
735
736 RETURN_RESULT_OR_FAILURE(
737 isolate, JSLocale::New(isolate, map, locale_string, options_object));
738 }
739
BUILTIN(LocalePrototypeMaximize)740 BUILTIN(LocalePrototypeMaximize) {
741 HandleScope scope(isolate);
742 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.maximize");
743 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Maximize(isolate, locale));
744 }
745
BUILTIN(LocalePrototypeMinimize)746 BUILTIN(LocalePrototypeMinimize) {
747 HandleScope scope(isolate);
748 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.minimize");
749 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Minimize(isolate, locale));
750 }
751
BUILTIN(LocalePrototypeCalendars)752 BUILTIN(LocalePrototypeCalendars) {
753 HandleScope scope(isolate);
754 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.calendars");
755 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Calendars(isolate, locale));
756 }
757
BUILTIN(LocalePrototypeCollations)758 BUILTIN(LocalePrototypeCollations) {
759 HandleScope scope(isolate);
760 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.collations");
761 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Collations(isolate, locale));
762 }
763
BUILTIN(LocalePrototypeHourCycles)764 BUILTIN(LocalePrototypeHourCycles) {
765 HandleScope scope(isolate);
766 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.hourCycles");
767 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::HourCycles(isolate, locale));
768 }
769
BUILTIN(LocalePrototypeNumberingSystems)770 BUILTIN(LocalePrototypeNumberingSystems) {
771 HandleScope scope(isolate);
772 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numberingSystems");
773 RETURN_RESULT_OR_FAILURE(isolate,
774 JSLocale::NumberingSystems(isolate, locale));
775 }
776
BUILTIN(LocalePrototypeTextInfo)777 BUILTIN(LocalePrototypeTextInfo) {
778 HandleScope scope(isolate);
779 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.textInfo");
780 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::TextInfo(isolate, locale));
781 }
782
BUILTIN(LocalePrototypeTimeZones)783 BUILTIN(LocalePrototypeTimeZones) {
784 HandleScope scope(isolate);
785 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.timeZones");
786 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::TimeZones(isolate, locale));
787 }
788
BUILTIN(LocalePrototypeWeekInfo)789 BUILTIN(LocalePrototypeWeekInfo) {
790 HandleScope scope(isolate);
791 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.weekInfo");
792 RETURN_RESULT_OR_FAILURE(isolate, JSLocale::WeekInfo(isolate, locale));
793 }
794
BUILTIN(RelativeTimeFormatSupportedLocalesOf)795 BUILTIN(RelativeTimeFormatSupportedLocalesOf) {
796 HandleScope scope(isolate);
797 Handle<Object> locales = args.atOrUndefined(isolate, 1);
798 Handle<Object> options = args.atOrUndefined(isolate, 2);
799
800 RETURN_RESULT_OR_FAILURE(
801 isolate,
802 Intl::SupportedLocalesOf(
803 isolate, "Intl.RelativeTimeFormat.supportedLocalesOf",
804 JSRelativeTimeFormat::GetAvailableLocales(), locales, options));
805 }
806
BUILTIN(RelativeTimeFormatPrototypeFormat)807 BUILTIN(RelativeTimeFormatPrototypeFormat) {
808 HandleScope scope(isolate);
809 // 1. Let relativeTimeFormat be the this value.
810 // 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not
811 // have an [[InitializedRelativeTimeFormat]] internal slot whose value is
812 // true, throw a TypeError exception.
813 CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
814 "Intl.RelativeTimeFormat.prototype.format");
815 Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
816 Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
817
818 RETURN_RESULT_OR_FAILURE(
819 isolate, JSRelativeTimeFormat::Format(isolate, value_obj, unit_obj,
820 format_holder));
821 }
822
BUILTIN(RelativeTimeFormatPrototypeFormatToParts)823 BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
824 HandleScope scope(isolate);
825 // 1. Let relativeTimeFormat be the this value.
826 // 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not
827 // have an [[InitializedRelativeTimeFormat]] internal slot whose value is
828 // true, throw a TypeError exception.
829 CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
830 "Intl.RelativeTimeFormat.prototype.formatToParts");
831 Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
832 Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
833 RETURN_RESULT_OR_FAILURE(
834 isolate, JSRelativeTimeFormat::FormatToParts(isolate, value_obj, unit_obj,
835 format_holder));
836 }
837
838 // Locale getters.
BUILTIN(LocalePrototypeLanguage)839 BUILTIN(LocalePrototypeLanguage) {
840 HandleScope scope(isolate);
841 // CHECK_RECEIVER will case locale_holder to JSLocale.
842 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.language");
843
844 return *JSLocale::Language(isolate, locale);
845 }
846
BUILTIN(LocalePrototypeScript)847 BUILTIN(LocalePrototypeScript) {
848 HandleScope scope(isolate);
849 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.script");
850
851 return *JSLocale::Script(isolate, locale);
852 }
853
BUILTIN(LocalePrototypeRegion)854 BUILTIN(LocalePrototypeRegion) {
855 HandleScope scope(isolate);
856 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.region");
857
858 return *JSLocale::Region(isolate, locale);
859 }
860
BUILTIN(LocalePrototypeBaseName)861 BUILTIN(LocalePrototypeBaseName) {
862 HandleScope scope(isolate);
863 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.baseName");
864
865 return *JSLocale::BaseName(isolate, locale);
866 }
867
BUILTIN(LocalePrototypeCalendar)868 BUILTIN(LocalePrototypeCalendar) {
869 HandleScope scope(isolate);
870 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.calendar");
871
872 return *JSLocale::Calendar(isolate, locale);
873 }
874
BUILTIN(LocalePrototypeCaseFirst)875 BUILTIN(LocalePrototypeCaseFirst) {
876 HandleScope scope(isolate);
877 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.caseFirst");
878
879 return *JSLocale::CaseFirst(isolate, locale);
880 }
881
BUILTIN(LocalePrototypeCollation)882 BUILTIN(LocalePrototypeCollation) {
883 HandleScope scope(isolate);
884 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.collation");
885
886 return *JSLocale::Collation(isolate, locale);
887 }
888
BUILTIN(LocalePrototypeHourCycle)889 BUILTIN(LocalePrototypeHourCycle) {
890 HandleScope scope(isolate);
891 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.hourCycle");
892
893 return *JSLocale::HourCycle(isolate, locale);
894 }
895
BUILTIN(LocalePrototypeNumeric)896 BUILTIN(LocalePrototypeNumeric) {
897 HandleScope scope(isolate);
898 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numeric");
899
900 return *JSLocale::Numeric(isolate, locale);
901 }
902
BUILTIN(LocalePrototypeNumberingSystem)903 BUILTIN(LocalePrototypeNumberingSystem) {
904 HandleScope scope(isolate);
905 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numberingSystem");
906
907 return *JSLocale::NumberingSystem(isolate, locale);
908 }
909
BUILTIN(LocalePrototypeToString)910 BUILTIN(LocalePrototypeToString) {
911 HandleScope scope(isolate);
912 CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.toString");
913
914 return *JSLocale::ToString(isolate, locale);
915 }
916
BUILTIN(RelativeTimeFormatConstructor)917 BUILTIN(RelativeTimeFormatConstructor) {
918 HandleScope scope(isolate);
919
920 return DisallowCallConstructor<JSRelativeTimeFormat>(
921 args, isolate, v8::Isolate::UseCounterFeature::kRelativeTimeFormat,
922 "Intl.RelativeTimeFormat");
923 }
924
BUILTIN(RelativeTimeFormatPrototypeResolvedOptions)925 BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) {
926 HandleScope scope(isolate);
927 CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
928 "Intl.RelativeTimeFormat.prototype.resolvedOptions");
929 return *JSRelativeTimeFormat::ResolvedOptions(isolate, format_holder);
930 }
931
BUILTIN(StringPrototypeToLocaleLowerCase)932 BUILTIN(StringPrototypeToLocaleLowerCase) {
933 HandleScope scope(isolate);
934
935 isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleLowerCase);
936
937 TO_THIS_STRING(string, "String.prototype.toLocaleLowerCase");
938
939 RETURN_RESULT_OR_FAILURE(
940 isolate, Intl::StringLocaleConvertCase(isolate, string, false,
941 args.atOrUndefined(isolate, 1)));
942 }
943
BUILTIN(StringPrototypeToLocaleUpperCase)944 BUILTIN(StringPrototypeToLocaleUpperCase) {
945 HandleScope scope(isolate);
946
947 isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleUpperCase);
948
949 TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase");
950
951 RETURN_RESULT_OR_FAILURE(
952 isolate, Intl::StringLocaleConvertCase(isolate, string, true,
953 args.atOrUndefined(isolate, 1)));
954 }
955
BUILTIN(PluralRulesConstructor)956 BUILTIN(PluralRulesConstructor) {
957 HandleScope scope(isolate);
958
959 return DisallowCallConstructor<JSPluralRules>(
960 args, isolate, v8::Isolate::UseCounterFeature::kPluralRules,
961 "Intl.PluralRules");
962 }
963
BUILTIN(PluralRulesPrototypeResolvedOptions)964 BUILTIN(PluralRulesPrototypeResolvedOptions) {
965 HandleScope scope(isolate);
966 CHECK_RECEIVER(JSPluralRules, plural_rules_holder,
967 "Intl.PluralRules.prototype.resolvedOptions");
968 return *JSPluralRules::ResolvedOptions(isolate, plural_rules_holder);
969 }
970
BUILTIN(PluralRulesPrototypeSelect)971 BUILTIN(PluralRulesPrototypeSelect) {
972 HandleScope scope(isolate);
973
974 // 1. 1. Let pr be the this value.
975 // 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
976 CHECK_RECEIVER(JSPluralRules, plural_rules,
977 "Intl.PluralRules.prototype.select");
978
979 // 3. Let n be ? ToNumber(value).
980 Handle<Object> number = args.atOrUndefined(isolate, 1);
981 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number,
982 Object::ToNumber(isolate, number));
983 double number_double = number->Number();
984
985 // 4. Return ! ResolvePlural(pr, n).
986 RETURN_RESULT_OR_FAILURE(isolate, JSPluralRules::ResolvePlural(
987 isolate, plural_rules, number_double));
988 }
989
BUILTIN(PluralRulesPrototypeSelectRange)990 BUILTIN(PluralRulesPrototypeSelectRange) {
991 HandleScope scope(isolate);
992
993 // 1. Let pr be the this value.
994 // 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
995 CHECK_RECEIVER(JSPluralRules, plural_rules,
996 "Intl.PluralRules.prototype.selectRange");
997
998 // 3. If start is undefined or end is undefined, throw a TypeError exception.
999 Handle<Object> start = args.atOrUndefined(isolate, 1);
1000 Handle<Object> end = args.atOrUndefined(isolate, 2);
1001 if (start->IsUndefined()) {
1002 THROW_NEW_ERROR_RETURN_FAILURE(
1003 isolate, NewTypeError(MessageTemplate::kInvalid,
1004 isolate->factory()->startRange_string(), start));
1005 }
1006 if (end->IsUndefined()) {
1007 THROW_NEW_ERROR_RETURN_FAILURE(
1008 isolate, NewTypeError(MessageTemplate::kInvalid,
1009 isolate->factory()->endRange_string(), end));
1010 }
1011
1012 // 4. Let x be ? ToNumber(start).
1013 Handle<Object> x;
1014 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
1015 Object::ToNumber(isolate, start));
1016
1017 // 5. Let y be ? ToNumber(end).
1018 Handle<Object> y;
1019 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, y,
1020 Object::ToNumber(isolate, end));
1021
1022 // 6. Return ! ResolvePluralRange(pr, x, y).
1023 // Inside ResolvePluralRange
1024 // 5. If x is NaN or y is NaN, throw a RangeError exception.
1025 if (x->IsNaN()) {
1026 THROW_NEW_ERROR_RETURN_FAILURE(
1027 isolate, NewRangeError(MessageTemplate::kInvalid,
1028 isolate->factory()->startRange_string(), x));
1029 }
1030 if (y->IsNaN()) {
1031 THROW_NEW_ERROR_RETURN_FAILURE(
1032 isolate, NewRangeError(MessageTemplate::kInvalid,
1033 isolate->factory()->endRange_string(), y));
1034 }
1035
1036 // 6. If x > y, throw a RangeError exception.
1037 double x_double = x->Number();
1038 double y_double = y->Number();
1039 if (x_double > y_double) {
1040 THROW_NEW_ERROR_RETURN_FAILURE(
1041 isolate, NewRangeError(MessageTemplate::kInvalid, x, y));
1042 }
1043 RETURN_RESULT_OR_FAILURE(
1044 isolate, JSPluralRules::ResolvePluralRange(isolate, plural_rules,
1045 x_double, y_double));
1046 }
1047
BUILTIN(PluralRulesSupportedLocalesOf)1048 BUILTIN(PluralRulesSupportedLocalesOf) {
1049 HandleScope scope(isolate);
1050 Handle<Object> locales = args.atOrUndefined(isolate, 1);
1051 Handle<Object> options = args.atOrUndefined(isolate, 2);
1052
1053 RETURN_RESULT_OR_FAILURE(
1054 isolate, Intl::SupportedLocalesOf(
1055 isolate, "Intl.PluralRules.supportedLocalesOf",
1056 JSPluralRules::GetAvailableLocales(), locales, options));
1057 }
1058
BUILTIN(CollatorConstructor)1059 BUILTIN(CollatorConstructor) {
1060 HandleScope scope(isolate);
1061
1062 isolate->CountUsage(v8::Isolate::UseCounterFeature::kCollator);
1063
1064 return CallOrConstructConstructor<JSCollator>(args, isolate, "Intl.Collator");
1065 }
1066
BUILTIN(CollatorPrototypeResolvedOptions)1067 BUILTIN(CollatorPrototypeResolvedOptions) {
1068 HandleScope scope(isolate);
1069 CHECK_RECEIVER(JSCollator, collator_holder,
1070 "Intl.Collator.prototype.resolvedOptions");
1071 return *JSCollator::ResolvedOptions(isolate, collator_holder);
1072 }
1073
BUILTIN(CollatorSupportedLocalesOf)1074 BUILTIN(CollatorSupportedLocalesOf) {
1075 HandleScope scope(isolate);
1076 Handle<Object> locales = args.atOrUndefined(isolate, 1);
1077 Handle<Object> options = args.atOrUndefined(isolate, 2);
1078
1079 RETURN_RESULT_OR_FAILURE(
1080 isolate, Intl::SupportedLocalesOf(
1081 isolate, "Intl.Collator.supportedLocalesOf",
1082 JSCollator::GetAvailableLocales(), locales, options));
1083 }
1084
BUILTIN(CollatorPrototypeCompare)1085 BUILTIN(CollatorPrototypeCompare) {
1086 const char* const method_name = "get Intl.Collator.prototype.compare";
1087 HandleScope scope(isolate);
1088
1089 // 1. Let collator be this value.
1090 // 2. If Type(collator) is not Object, throw a TypeError exception.
1091 // 3. If collator does not have an [[InitializedCollator]] internal slot,
1092 // throw a TypeError exception.
1093 CHECK_RECEIVER(JSCollator, collator, method_name);
1094
1095 // 4. If collator.[[BoundCompare]] is undefined, then
1096 Handle<Object> bound_compare(collator->bound_compare(), isolate);
1097 if (!bound_compare->IsUndefined(isolate)) {
1098 DCHECK(bound_compare->IsJSFunction());
1099 // 5. Return collator.[[BoundCompare]].
1100 return *bound_compare;
1101 }
1102
1103 Handle<JSFunction> new_bound_compare_function = CreateBoundFunction(
1104 isolate, collator, Builtin::kCollatorInternalCompare, 2);
1105
1106 // 4.c. Set collator.[[BoundCompare]] to F.
1107 collator->set_bound_compare(*new_bound_compare_function);
1108
1109 // 5. Return collator.[[BoundCompare]].
1110 return *new_bound_compare_function;
1111 }
1112
BUILTIN(CollatorInternalCompare)1113 BUILTIN(CollatorInternalCompare) {
1114 HandleScope scope(isolate);
1115 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1116
1117 // 1. Let collator be F.[[Collator]].
1118 // 2. Assert: Type(collator) is Object and collator has an
1119 // [[InitializedCollator]] internal slot.
1120 Handle<JSCollator> collator = Handle<JSCollator>(
1121 JSCollator::cast(context->get(
1122 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1123 isolate);
1124
1125 // 3. If x is not provided, let x be undefined.
1126 Handle<Object> x = args.atOrUndefined(isolate, 1);
1127 // 4. If y is not provided, let y be undefined.
1128 Handle<Object> y = args.atOrUndefined(isolate, 2);
1129
1130 // 5. Let X be ? ToString(x).
1131 Handle<String> string_x;
1132 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_x,
1133 Object::ToString(isolate, x));
1134 // 6. Let Y be ? ToString(y).
1135 Handle<String> string_y;
1136 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_y,
1137 Object::ToString(isolate, y));
1138
1139 // 7. Return CompareStrings(collator, X, Y).
1140 icu::Collator* icu_collator = collator->icu_collator().raw();
1141 CHECK_NOT_NULL(icu_collator);
1142 return Smi::FromInt(
1143 Intl::CompareStrings(isolate, *icu_collator, string_x, string_y));
1144 }
1145
1146 // ecma402 #sec-%segmentiteratorprototype%.next
BUILTIN(SegmentIteratorPrototypeNext)1147 BUILTIN(SegmentIteratorPrototypeNext) {
1148 const char* const method_name = "%SegmentIterator.prototype%.next";
1149 HandleScope scope(isolate);
1150 CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method_name);
1151
1152 RETURN_RESULT_OR_FAILURE(isolate,
1153 JSSegmentIterator::Next(isolate, segment_iterator));
1154 }
1155
1156 // ecma402 #sec-intl.segmenter
BUILTIN(SegmenterConstructor)1157 BUILTIN(SegmenterConstructor) {
1158 HandleScope scope(isolate);
1159
1160 return DisallowCallConstructor<JSSegmenter>(
1161 args, isolate, v8::Isolate::UseCounterFeature::kSegmenter,
1162 "Intl.Segmenter");
1163 }
1164
1165 // ecma402 #sec-intl.segmenter.supportedlocalesof
BUILTIN(SegmenterSupportedLocalesOf)1166 BUILTIN(SegmenterSupportedLocalesOf) {
1167 HandleScope scope(isolate);
1168 Handle<Object> locales = args.atOrUndefined(isolate, 1);
1169 Handle<Object> options = args.atOrUndefined(isolate, 2);
1170
1171 RETURN_RESULT_OR_FAILURE(
1172 isolate, Intl::SupportedLocalesOf(
1173 isolate, "Intl.Segmenter.supportedLocalesOf",
1174 JSSegmenter::GetAvailableLocales(), locales, options));
1175 }
1176
1177 // ecma402 #sec-intl.segmenter.prototype.resolvedoptions
BUILTIN(SegmenterPrototypeResolvedOptions)1178 BUILTIN(SegmenterPrototypeResolvedOptions) {
1179 HandleScope scope(isolate);
1180 CHECK_RECEIVER(JSSegmenter, segmenter,
1181 "Intl.Segmenter.prototype.resolvedOptions");
1182 return *JSSegmenter::ResolvedOptions(isolate, segmenter);
1183 }
1184
1185 // ecma402 #sec-intl.segmenter.prototype.segment
BUILTIN(SegmenterPrototypeSegment)1186 BUILTIN(SegmenterPrototypeSegment) {
1187 HandleScope scope(isolate);
1188 CHECK_RECEIVER(JSSegmenter, segmenter, "Intl.Segmenter.prototype.segment");
1189 Handle<Object> input_text = args.atOrUndefined(isolate, 1);
1190 // 3. Let string be ? ToString(string).
1191 Handle<String> string;
1192 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
1193 Object::ToString(isolate, input_text));
1194
1195 // 4. Return ? CreateSegmentsObject(segmenter, string).
1196 RETURN_RESULT_OR_FAILURE(isolate,
1197 JSSegments::Create(isolate, segmenter, string));
1198 }
1199
1200 // ecma402 #sec-%segmentsprototype%.containing
BUILTIN(SegmentsPrototypeContaining)1201 BUILTIN(SegmentsPrototypeContaining) {
1202 const char* const method_name = "%Segments.prototype%.containing";
1203 HandleScope scope(isolate);
1204 CHECK_RECEIVER(JSSegments, segments, method_name);
1205 Handle<Object> index = args.atOrUndefined(isolate, 1);
1206
1207 // 6. Let n be ? ToInteger(index).
1208 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, index,
1209 Object::ToInteger(isolate, index));
1210 double const n = index->Number();
1211
1212 RETURN_RESULT_OR_FAILURE(isolate,
1213 JSSegments::Containing(isolate, segments, n));
1214 }
1215
1216 // ecma402 #sec-%segmentsprototype%-@@iterator
BUILTIN(SegmentsPrototypeIterator)1217 BUILTIN(SegmentsPrototypeIterator) {
1218 const char* const method_name = "%SegmentIsPrototype%[@@iterator]";
1219 HandleScope scope(isolate);
1220 CHECK_RECEIVER(JSSegments, segments, method_name);
1221 RETURN_RESULT_OR_FAILURE(
1222 isolate,
1223 JSSegmentIterator::Create(isolate, segments->icu_break_iterator().raw(),
1224 segments->granularity()));
1225 }
1226
BUILTIN(V8BreakIteratorConstructor)1227 BUILTIN(V8BreakIteratorConstructor) {
1228 HandleScope scope(isolate);
1229
1230 return CallOrConstructConstructor<JSV8BreakIterator>(args, isolate,
1231 "Intl.v8BreakIterator");
1232 }
1233
BUILTIN(V8BreakIteratorPrototypeResolvedOptions)1234 BUILTIN(V8BreakIteratorPrototypeResolvedOptions) {
1235 HandleScope scope(isolate);
1236 CHECK_RECEIVER(JSV8BreakIterator, break_iterator,
1237 "Intl.v8BreakIterator.prototype.resolvedOptions");
1238 return *JSV8BreakIterator::ResolvedOptions(isolate, break_iterator);
1239 }
1240
BUILTIN(V8BreakIteratorPrototypeAdoptText)1241 BUILTIN(V8BreakIteratorPrototypeAdoptText) {
1242 const char* const method_name =
1243 "get Intl.v8BreakIterator.prototype.adoptText";
1244 HandleScope scope(isolate);
1245
1246 CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
1247
1248 Handle<Object> bound_adopt_text(break_iterator->bound_adopt_text(), isolate);
1249 if (!bound_adopt_text->IsUndefined(isolate)) {
1250 DCHECK(bound_adopt_text->IsJSFunction());
1251 return *bound_adopt_text;
1252 }
1253
1254 Handle<JSFunction> new_bound_adopt_text_function = CreateBoundFunction(
1255 isolate, break_iterator, Builtin::kV8BreakIteratorInternalAdoptText, 1);
1256 break_iterator->set_bound_adopt_text(*new_bound_adopt_text_function);
1257 return *new_bound_adopt_text_function;
1258 }
1259
BUILTIN(V8BreakIteratorInternalAdoptText)1260 BUILTIN(V8BreakIteratorInternalAdoptText) {
1261 HandleScope scope(isolate);
1262 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1263
1264 Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
1265 JSV8BreakIterator::cast(context->get(
1266 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1267 isolate);
1268
1269 Handle<Object> input_text = args.atOrUndefined(isolate, 1);
1270 Handle<String> text;
1271 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, text,
1272 Object::ToString(isolate, input_text));
1273
1274 JSV8BreakIterator::AdoptText(isolate, break_iterator, text);
1275 return ReadOnlyRoots(isolate).undefined_value();
1276 }
1277
BUILTIN(V8BreakIteratorPrototypeFirst)1278 BUILTIN(V8BreakIteratorPrototypeFirst) {
1279 const char* const method_name = "get Intl.v8BreakIterator.prototype.first";
1280 HandleScope scope(isolate);
1281
1282 CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
1283
1284 Handle<Object> bound_first(break_iterator->bound_first(), isolate);
1285 if (!bound_first->IsUndefined(isolate)) {
1286 DCHECK(bound_first->IsJSFunction());
1287 return *bound_first;
1288 }
1289
1290 Handle<JSFunction> new_bound_first_function = CreateBoundFunction(
1291 isolate, break_iterator, Builtin::kV8BreakIteratorInternalFirst, 0);
1292 break_iterator->set_bound_first(*new_bound_first_function);
1293 return *new_bound_first_function;
1294 }
1295
BUILTIN(V8BreakIteratorInternalFirst)1296 BUILTIN(V8BreakIteratorInternalFirst) {
1297 HandleScope scope(isolate);
1298 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1299
1300 Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
1301 JSV8BreakIterator::cast(context->get(
1302 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1303 isolate);
1304
1305 return *JSV8BreakIterator::First(isolate, break_iterator);
1306 }
1307
BUILTIN(V8BreakIteratorPrototypeNext)1308 BUILTIN(V8BreakIteratorPrototypeNext) {
1309 const char* const method_name = "get Intl.v8BreakIterator.prototype.next";
1310 HandleScope scope(isolate);
1311
1312 CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
1313
1314 Handle<Object> bound_next(break_iterator->bound_next(), isolate);
1315 if (!bound_next->IsUndefined(isolate)) {
1316 DCHECK(bound_next->IsJSFunction());
1317 return *bound_next;
1318 }
1319
1320 Handle<JSFunction> new_bound_next_function = CreateBoundFunction(
1321 isolate, break_iterator, Builtin::kV8BreakIteratorInternalNext, 0);
1322 break_iterator->set_bound_next(*new_bound_next_function);
1323 return *new_bound_next_function;
1324 }
1325
BUILTIN(V8BreakIteratorInternalNext)1326 BUILTIN(V8BreakIteratorInternalNext) {
1327 HandleScope scope(isolate);
1328 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1329
1330 Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
1331 JSV8BreakIterator::cast(context->get(
1332 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1333 isolate);
1334 return *JSV8BreakIterator::Next(isolate, break_iterator);
1335 }
1336
BUILTIN(V8BreakIteratorPrototypeCurrent)1337 BUILTIN(V8BreakIteratorPrototypeCurrent) {
1338 const char* const method_name = "get Intl.v8BreakIterator.prototype.current";
1339 HandleScope scope(isolate);
1340
1341 CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
1342
1343 Handle<Object> bound_current(break_iterator->bound_current(), isolate);
1344 if (!bound_current->IsUndefined(isolate)) {
1345 DCHECK(bound_current->IsJSFunction());
1346 return *bound_current;
1347 }
1348
1349 Handle<JSFunction> new_bound_current_function = CreateBoundFunction(
1350 isolate, break_iterator, Builtin::kV8BreakIteratorInternalCurrent, 0);
1351 break_iterator->set_bound_current(*new_bound_current_function);
1352 return *new_bound_current_function;
1353 }
1354
BUILTIN(V8BreakIteratorInternalCurrent)1355 BUILTIN(V8BreakIteratorInternalCurrent) {
1356 HandleScope scope(isolate);
1357 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1358
1359 Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
1360 JSV8BreakIterator::cast(context->get(
1361 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1362 isolate);
1363 return *JSV8BreakIterator::Current(isolate, break_iterator);
1364 }
1365
BUILTIN(V8BreakIteratorPrototypeBreakType)1366 BUILTIN(V8BreakIteratorPrototypeBreakType) {
1367 const char* const method_name =
1368 "get Intl.v8BreakIterator.prototype.breakType";
1369 HandleScope scope(isolate);
1370
1371 CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
1372
1373 Handle<Object> bound_break_type(break_iterator->bound_break_type(), isolate);
1374 if (!bound_break_type->IsUndefined(isolate)) {
1375 DCHECK(bound_break_type->IsJSFunction());
1376 return *bound_break_type;
1377 }
1378
1379 Handle<JSFunction> new_bound_break_type_function = CreateBoundFunction(
1380 isolate, break_iterator, Builtin::kV8BreakIteratorInternalBreakType, 0);
1381 break_iterator->set_bound_break_type(*new_bound_break_type_function);
1382 return *new_bound_break_type_function;
1383 }
1384
BUILTIN(V8BreakIteratorInternalBreakType)1385 BUILTIN(V8BreakIteratorInternalBreakType) {
1386 HandleScope scope(isolate);
1387 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
1388
1389 Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
1390 JSV8BreakIterator::cast(context->get(
1391 static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
1392 isolate);
1393 return JSV8BreakIterator::BreakType(isolate, break_iterator);
1394 }
1395
1396 } // namespace internal
1397 } // namespace v8
1398